diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php
index f461b525152530cb15a8a2ea8964c6170390aa09..df98969c262cea0b631504f57abd1353c4ab26d3 100644
--- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php
+++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php
@@ -192,7 +192,14 @@ class Toolbar extends \Magento\Framework\View\Element\Template
             $this->_collection->setPageSize($limit);
         }
         if ($this->getCurrentOrder()) {
-            $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
+            if ($this->getCurrentOrder() == 'position') {
+                $this->_collection->addAttributeToSort(
+                    $this->getCurrentOrder(),
+                    $this->getCurrentDirection()
+                )->addAttributeToSort('entity_id', $this->getCurrentDirection());
+            } else {
+                $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
+            }
         }
         return $this;
     }
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php
index 24d81f0054c5a1bde1f90ab1212bd629e36c81ec..8f0e6e9c0cdb5c60d1a065f4176a2aed829071d8 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php
@@ -369,25 +369,55 @@ class AbstractAction
         }
         $values = [];
 
-        foreach ($entityIds as $entityId) {
-            $values[$entityId] = [];
+        $linkIds = $this->getLinkIds($entityIds);
+        foreach ($linkIds as $linkId) {
+            $values[$linkId] = [];
         }
+
         $attributes = $this->getAttributes();
         $attributesType = ['varchar', 'int', 'decimal', 'text', 'datetime'];
+        $linkField = $this->getCategoryMetadata()->getLinkField();
         foreach ($attributesType as $type) {
             foreach ($this->getAttributeTypeValues($type, $entityIds, $storeId) as $row) {
-                if (isset($row[$this->getCategoryMetadata()->getLinkField()]) && isset($row['attribute_id'])) {
+                if (isset($row[$linkField]) && isset($row['attribute_id'])) {
                     $attributeId = $row['attribute_id'];
                     if (isset($attributes[$attributeId])) {
                         $attributeCode = $attributes[$attributeId]['attribute_code'];
-                        $values[$row[$this->getCategoryMetadata()->getLinkField()]][$attributeCode] = $row['value'];
+                        $values[$row[$linkField]][$attributeCode] = $row['value'];
                     }
                 }
             }
         }
+
         return $values;
     }
 
+    /**
+     * Translate entity ids into link ids
+     *
+     * Used for rows with no EAV attributes set.
+     *
+     * @param array $entityIds
+     * @return array
+     */
+    private function getLinkIds(array $entityIds)
+    {
+        $linkField = $this->getCategoryMetadata()->getLinkField();
+        if ($linkField === 'entity_id') {
+            return $entityIds;
+        }
+
+        $select = $this->connection->select()->from(
+            ['e' => $this->connection->getTableName($this->getTableName('catalog_category_entity'))],
+            [$linkField]
+        )->where(
+            'e.entity_id IN (?)',
+            $entityIds
+        );
+
+        return $this->connection->fetchCol($select);
+    }
+
     /**
      * Return attribute values for given entities and store of specific attribute type
      *
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Full.php
index eeac2e80af97e355233457518db92cf9ea86d31d..64a8f930d83ee4ab2298bb69fd0f597ad0f53755 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Full.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Full.php
@@ -64,18 +64,22 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Flat\AbstractAction
             }
             /** @TODO Do something with chunks */
             $categoriesIdsChunks = array_chunk($categoriesIds[$store->getRootCategoryId()], 500);
+
             foreach ($categoriesIdsChunks as $categoriesIdsChunk) {
                 $attributesData = $this->getAttributeValues($categoriesIdsChunk, $store->getId());
+                $linkField = $this->categoryMetadata->getLinkField();
+
                 $data = [];
                 foreach ($categories[$store->getRootCategoryId()] as $category) {
-                    if (!isset($attributesData[$category[$this->categoryMetadata->getLinkField()]])) {
+                    if (!isset($attributesData[$category[$linkField]])) {
                         continue;
                     }
                     $category['store_id'] = $store->getId();
                     $data[] = $this->prepareValuesToInsert(
-                        array_merge($category, $attributesData[$category[$this->categoryMetadata->getLinkField()]])
+                        array_merge($category, $attributesData[$category[$linkField]])
                     );
                 }
+
                 $this->connection->insertMultiple(
                     $this->addTemporaryTableSuffix($this->getMainStoreTable($store->getId())),
                     $data
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Rows.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Rows.php
index 2368c27e02d72b1e64fcc5c23a29b01e0f10436e..bc17d731f04c0a00cf1c0e62300bbba33230de68 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Rows.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Rows.php
@@ -69,22 +69,24 @@ class Rows extends \Magento\Catalog\Model\Indexer\Category\Flat\AbstractAction
                 $categoriesIdsChunk = $this->filterIdsByStore($categoriesIdsChunk, $store);
 
                 $attributesData = $this->getAttributeValues($categoriesIdsChunk, $store->getId());
+                $linkField = $this->categoryMetadata->getLinkField();
                 $data = [];
                 foreach ($categoriesIdsChunk as $categoryId) {
-                    if (!isset($attributesData[$categoryId])) {
-                        continue;
-                    }
-
                     try {
                         $category = $this->categoryRepository->get($categoryId);
                     } catch (NoSuchEntityException $e) {
                         continue;
                     }
 
+                    $categoryData = $category->getData();
+                    if (!isset($attributesData[$categoryData[$linkField]])) {
+                        continue;
+                    }
+
                     $data[] = $this->prepareValuesToInsert(
                         array_merge(
-                            $category->getData(),
-                            $attributesData[$categoryId],
+                            $categoryData,
+                            $attributesData[$categoryData[$linkField]],
                             ['store_id' => $store->getId()]
                         )
                     );
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index cf1392a7e9e8c80082d8375f4d6b1ccb02492532..cb5669a4bb42e9215efada3b49885d8fd013b62f 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -1712,7 +1712,7 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
      * Get attribute text by its code
      *
      * @param string $attributeCode Code of the attribute
-     * @return string
+     * @return string|array|null
      */
     public function getAttributeText($attributeCode)
     {
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Value.php b/app/code/Magento/Catalog/Model/Product/Option/Value.php
index 0e86510ebcee7f82f96fc250e07940e664ca5971..d4c78772e7c0be357ac95845dc8f3f1f56d1a72f 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Value.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Value.php
@@ -190,6 +190,7 @@ class Value extends AbstractModel implements \Magento\Catalog\Api\Data\ProductCu
     public function saveValues()
     {
         foreach ($this->getValues() as $value) {
+            $this->isDeleted(false);
             $this->setData(
                 $value
             )->setData(
diff --git a/app/code/Magento/Customer/Controller/Ajax/Login.php b/app/code/Magento/Customer/Controller/Ajax/Login.php
index f1384ba188a0a113abb269e0621082a531ff3293..8664e0cbf87ea3abdcf36a16340ead10fd432c74 100644
--- a/app/code/Magento/Customer/Controller/Ajax/Login.php
+++ b/app/code/Magento/Customer/Controller/Ajax/Login.php
@@ -13,6 +13,8 @@ use Magento\Framework\App\ObjectManager;
 use Magento\Customer\Model\Account\Redirect as AccountRedirect;
 use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Stdlib\CookieManagerInterface;
+use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory;
 
 /**
  * Login controller
@@ -58,6 +60,16 @@ class Login extends \Magento\Framework\App\Action\Action
      */
     protected $scopeConfig;
 
+    /**
+     * @var CookieManagerInterface
+     */
+    private $cookieManager;
+
+    /**
+     * @var CookieMetadataFactory
+     */
+    private $cookieMetadataFactory;
+
     /**
      * Initialize Login controller
      *
@@ -67,6 +79,8 @@ class Login extends \Magento\Framework\App\Action\Action
      * @param AccountManagementInterface $customerAccountManagement
      * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
      * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
+     * @param CookieManagerInterface $cookieManager
+     * @param CookieMetadataFactory $cookieMetadataFactory
      */
     public function __construct(
         \Magento\Framework\App\Action\Context $context,
@@ -74,7 +88,9 @@ class Login extends \Magento\Framework\App\Action\Action
         \Magento\Framework\Json\Helper\Data $helper,
         AccountManagementInterface $customerAccountManagement,
         \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
-        \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
+        \Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
+        CookieManagerInterface $cookieManager = null,
+        CookieMetadataFactory $cookieMetadataFactory = null
     ) {
         parent::__construct($context);
         $this->customerSession = $customerSession;
@@ -82,6 +98,12 @@ class Login extends \Magento\Framework\App\Action\Action
         $this->customerAccountManagement = $customerAccountManagement;
         $this->resultJsonFactory = $resultJsonFactory;
         $this->resultRawFactory = $resultRawFactory;
+        $this->cookieManager = $cookieManager ?: ObjectManager::getInstance()->get(
+            CookieManagerInterface::class
+        );
+        $this->cookieMetadataFactory = $cookieMetadataFactory ?: ObjectManager::getInstance()->get(
+            CookieMetadataFactory::class
+        );
     }
 
     /**
@@ -169,6 +191,11 @@ class Login extends \Magento\Framework\App\Action\Action
             $this->customerSession->setCustomerDataAsLoggedIn($customer);
             $this->customerSession->regenerateId();
             $redirectRoute = $this->getAccountRedirect()->getRedirectCookie();
+            if ($this->cookieManager->getCookie('mage-cache-sessid')) {
+                $metadata = $this->cookieMetadataFactory->createCookieMetadata();
+                $metadata->setPath('/');
+                $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
+            }
             if (!$this->getScopeConfig()->getValue('customer/startup/redirect_dashboard') && $redirectRoute) {
                 $response['redirectUrl'] = $this->_redirect->success($redirectRoute);
                 $this->getAccountRedirect()->clearRedirectCookie();
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php
index b759b1a62573f45d6621bcc7a786e25ff03ec993..2fca6c99be31993f6e1cd59ce53b849cbb04ad9c 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php
@@ -73,6 +73,21 @@ class LoginTest extends \PHPUnit\Framework\TestCase
      */
     protected $redirectMock;
 
+    /**
+     * @var \Magento\Framework\Stdlib\CookieManagerInterface| \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cookieManager;
+
+    /**
+     * @var \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory| \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cookieMetadataFactory;
+
+    /**
+     * @var \Magento\Framework\Stdlib\Cookie\CookieMetadata| \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cookieMetadata;
+
     protected function setUp()
     {
         $this->request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class)
@@ -100,6 +115,16 @@ class LoginTest extends \PHPUnit\Framework\TestCase
             ->setMethods(['create'])
             ->getMock();
 
+        $this->cookieManager = $this->getMockBuilder(\Magento\Framework\Stdlib\CookieManagerInterface::class)
+            ->setMethods(['getCookie', 'deleteCookie'])
+            ->getMockForAbstractClass();
+        $this->cookieMetadataFactory = $this->getMockBuilder(\Magento\Framework\Stdlib\Cookie\CookieMetadataFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->cookieMetadata = $this->getMockBuilder(\Magento\Framework\Stdlib\Cookie\CookieMetadata::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->resultRaw = $this->getMockBuilder(\Magento\Framework\Controller\Result\Raw::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -128,6 +153,8 @@ class LoginTest extends \PHPUnit\Framework\TestCase
                 'resultJsonFactory' => $this->resultJsonFactory,
                 'objectManager' => $this->objectManager,
                 'customerAccountManagement' => $this->customerAccountManagementMock,
+                'cookieManager' => $this->cookieManager,
+                'cookieMetadataFactory' => $this->cookieMetadataFactory
             ]
         );
     }
@@ -179,6 +206,22 @@ class LoginTest extends \PHPUnit\Framework\TestCase
         $this->object->setAccountRedirect($redirectMock);
         $redirectMock->expects($this->once())->method('getRedirectCookie')->willReturn('some_url1');
 
+        $this->cookieManager->expects($this->once())
+            ->method('getCookie')
+            ->with('mage-cache-sessid')
+            ->willReturn(true);
+        $this->cookieMetadataFactory->expects($this->once())
+            ->method('createCookieMetadata')
+            ->willReturn($this->cookieMetadata);
+        $this->cookieMetadata->expects($this->once())
+            ->method('setPath')
+            ->with('/')
+            ->willReturnSelf();
+        $this->cookieManager->expects($this->once())
+            ->method('deleteCookie')
+            ->with('mage-cache-sessid', $this->cookieMetadata)
+            ->willReturnSelf();
+
         $scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
         $this->object->setScopeConfig($scopeConfigMock);
         $scopeConfigMock->expects($this->once())->method('getValue')
diff --git a/app/code/Magento/Directory/Model/Currency.php b/app/code/Magento/Directory/Model/Currency.php
index a8df4936b8fae8ba0ece3f90a1efb3e01519fb0c..0b5b836b4ac93933b65c44f9d4447722dabc1c3a 100644
--- a/app/code/Magento/Directory/Model/Currency.php
+++ b/app/code/Magento/Directory/Model/Currency.php
@@ -6,6 +6,7 @@
 
 namespace Magento\Directory\Model;
 
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Exception\InputException;
 use Magento\Directory\Model\Currency\Filter;
 
@@ -65,6 +66,11 @@ class Currency extends \Magento\Framework\Model\AbstractModel
      */
     protected $_localeCurrency;
 
+    /**
+     * @var CurrencyConfig
+     */
+    private $currencyConfig;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -76,6 +82,7 @@ class Currency extends \Magento\Framework\Model\AbstractModel
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
+     * @param CurrencyConfig $currencyConfig
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -88,7 +95,8 @@ class Currency extends \Magento\Framework\Model\AbstractModel
         \Magento\Framework\Locale\CurrencyInterface $localeCurrency,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        CurrencyConfig $currencyConfig = null
     ) {
         parent::__construct(
             $context,
@@ -102,6 +110,7 @@ class Currency extends \Magento\Framework\Model\AbstractModel
         $this->_directoryHelper = $directoryHelper;
         $this->_currencyFilterFactory = $currencyFilterFactory;
         $this->_localeCurrency = $localeCurrency;
+        $this->currencyConfig = $currencyConfig ?: ObjectManager::getInstance()->get(CurrencyConfig::class);
     }
 
     /**
@@ -347,7 +356,7 @@ class Currency extends \Magento\Framework\Model\AbstractModel
      */
     public function getConfigAllowCurrencies()
     {
-        $allowedCurrencies = $this->_getResource()->getConfigCurrencies($this, self::XML_PATH_CURRENCY_ALLOW);
+        $allowedCurrencies = $this->currencyConfig->getConfigCurrencies(self::XML_PATH_CURRENCY_ALLOW);
         $appBaseCurrencyCode = $this->_directoryHelper->getBaseCurrencyCode();
         if (!in_array($appBaseCurrencyCode, $allowedCurrencies)) {
             $allowedCurrencies[] = $appBaseCurrencyCode;
@@ -369,8 +378,7 @@ class Currency extends \Magento\Framework\Model\AbstractModel
      */
     public function getConfigDefaultCurrencies()
     {
-        $defaultCurrencies = $this->_getResource()->getConfigCurrencies($this, self::XML_PATH_CURRENCY_DEFAULT);
-        return $defaultCurrencies;
+        return $this->currencyConfig->getConfigCurrencies(self::XML_PATH_CURRENCY_DEFAULT);
     }
 
     /**
@@ -378,8 +386,7 @@ class Currency extends \Magento\Framework\Model\AbstractModel
      */
     public function getConfigBaseCurrencies()
     {
-        $defaultCurrencies = $this->_getResource()->getConfigCurrencies($this, self::XML_PATH_CURRENCY_BASE);
-        return $defaultCurrencies;
+        return $this->currencyConfig->getConfigCurrencies(self::XML_PATH_CURRENCY_BASE);
     }
 
     /**
diff --git a/app/code/Magento/Directory/Model/CurrencyConfig.php b/app/code/Magento/Directory/Model/CurrencyConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..fdb561c2241706c83daf0b389319c59847ddfe93
--- /dev/null
+++ b/app/code/Magento/Directory/Model/CurrencyConfig.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Directory\Model;
+
+use Magento\Framework\App\Area;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\State;
+use Magento\Store\Model\ScopeInterface;
+use Magento\Store\Model\StoreManagerInterface;
+
+/**
+ * Provide config values for allowed, base and default currencies.
+ */
+class CurrencyConfig
+{
+    /**
+     * @var State
+     */
+    private $appState;
+
+    /**
+     * @var ScopeConfigInterface
+     */
+    private $config;
+
+    /**
+     * @var StoreManagerInterface
+     */
+    private $storeManager;
+
+    /**
+     * CurrencyConfig constructor.
+     *
+     * @param State $appState
+     * @param ScopeConfigInterface $config
+     * @param StoreManagerInterface $storeManager
+     */
+    public function __construct(
+        State $appState,
+        ScopeConfigInterface $config,
+        StoreManagerInterface $storeManager
+    ) {
+        $this->appState = $appState;
+        $this->config = $config;
+        $this->storeManager = $storeManager;
+    }
+
+    /**
+     * Retrieve config currency data by config path.
+     *
+     * @param string $path
+     * @return array
+     */
+    public function getConfigCurrencies(string $path)
+    {
+        $result = $this->appState->getAreaCode() === Area::AREA_ADMINHTML
+            ? $this->getConfigForAllStores($path)
+            : $this->getConfigForCurrentStore($path);
+        sort($result);
+
+        return array_unique($result);
+    }
+
+    /**
+     * Get allowed, base and default currency codes for all stores.
+     *
+     * @param string $path
+     * @return array
+     */
+    private function getConfigForAllStores(string $path)
+    {
+        $storesResult = [[]];
+        foreach ($this->storeManager->getStores() as $store) {
+            $storesResult[] = explode(
+                ',',
+                $this->config->getValue($path, ScopeInterface::SCOPE_STORE, $store->getCode())
+            );
+        }
+
+        return array_merge(...$storesResult);
+    }
+
+    /**
+     * Get allowed, base and default currency codes for current store.
+     *
+     * @param string $path
+     * @return mixed
+     */
+    private function getConfigForCurrentStore(string $path)
+    {
+        $store = $this->storeManager->getStore();
+
+        return explode(',', $this->config->getValue($path, ScopeInterface::SCOPE_STORE, $store->getCode()));
+    }
+}
diff --git a/app/code/Magento/Directory/Model/ResourceModel/Currency.php b/app/code/Magento/Directory/Model/ResourceModel/Currency.php
index ac0716fc4e67e0bc5dc07900fd95104e8a8d56f9..ffbcce11cb4f62a17196d92d240879db52edb626 100644
--- a/app/code/Magento/Directory/Model/ResourceModel/Currency.php
+++ b/app/code/Magento/Directory/Model/ResourceModel/Currency.php
@@ -165,6 +165,8 @@ class Currency extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
      * @param string $path
      * @return array
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @deprecated because doesn't take into consideration scopes and system config values.
+     * @see \Magento\Directory\Model\CurrencyConfig::getConfigCurrencies()
      */
     public function getConfigCurrencies($model, $path)
     {
diff --git a/app/code/Magento/Directory/Test/Unit/Model/CurrencyConfigTest.php b/app/code/Magento/Directory/Test/Unit/Model/CurrencyConfigTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b52bae26f90fd65298a0cbf6df97dd483eb77b2
--- /dev/null
+++ b/app/code/Magento/Directory/Test/Unit/Model/CurrencyConfigTest.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Directory\Test\Unit\Model;
+
+use Magento\Config\App\Config\Type\System;
+use Magento\Directory\Model\CurrencyConfig;
+use Magento\Framework\App\Area;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\State;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Store\Api\Data\StoreInterface;
+use Magento\Store\Model\StoreManagerInterface;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Provide tests for CurrencyConfig model.
+ */
+class CurrencyConfigTest extends TestCase
+{
+    /**
+     * @var CurrencyConfig
+     */
+    private $testSubject;
+
+    /**
+     * @var System|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $config;
+
+    /**
+     * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManager;
+
+    /**
+     * @var State|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $appState;
+
+    /**
+     * @inheritdoc
+     */
+    protected function setUp()
+    {
+        $this->config = $this->getMockBuilder(ScopeConfigInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->storeManager = $this->getMockBuilder(StoreManagerInterface::class)
+            ->setMethods(['getStores', 'getWebsites'])
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->appState = $this->getMockBuilder(State::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $objectManager = new ObjectManager($this);
+        $this->testSubject = $objectManager->getObject(
+            CurrencyConfig::class,
+            [
+                'storeManager' => $this->storeManager,
+                'appState' => $this->appState,
+                'config' => $this->config,
+            ]
+        );
+    }
+
+    /**
+     * Test get currency config for admin and storefront areas.
+     *
+     * @dataProvider getConfigCurrenciesDataProvider
+     * @return void
+     */
+    public function testGetConfigCurrencies(string $areCode)
+    {
+        $path = 'test/path';
+        $expected = ['ARS', 'AUD', 'BZD'];
+
+        $this->appState->expects(self::once())
+            ->method('getAreaCode')
+            ->willReturn($areCode);
+
+        /** @var StoreInterface|\PHPUnit_Framework_MockObject_MockObject $store */
+        $store = $this->getMockBuilder(StoreInterface::class)
+            ->setMethods(['getCode'])
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $store->expects(self::once())
+            ->method('getCode')
+            ->willReturn('testCode');
+
+        if ($areCode === Area::AREA_ADMINHTML) {
+            $this->storeManager->expects(self::once())
+                ->method('getStores')
+                ->willReturn([$store]);
+        } else {
+            $this->storeManager->expects(self::once())
+                ->method('getStore')
+                ->willReturn($store);
+        }
+
+        $this->config->expects(self::once())
+            ->method('getValue')
+            ->with(
+                self::identicalTo($path)
+            )->willReturn('ARS,AUD,BZD');
+
+        $result = $this->testSubject->getConfigCurrencies($path);
+
+        self::assertEquals($expected, $result);
+    }
+
+    /**
+     * Provide test data for getConfigCurrencies test.
+     *
+     * @return array
+     */
+    public function getConfigCurrenciesDataProvider()
+    {
+        return [
+            ['areaCode' => Area::AREA_ADMINHTML],
+            ['areaCode' => Area::AREA_FRONTEND],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php
index c2f03ff5d9ac4cafe0356fc8f4455b167882b206..69f4d19e4dd630a45242df8e507de199525602d5 100644
--- a/app/code/Magento/Sales/Model/AdminOrder/Create.php
+++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php
@@ -10,9 +10,12 @@ namespace Magento\Sales\Model\AdminOrder;
 
 use Magento\Customer\Api\AddressMetadataInterface;
 use Magento\Customer\Model\Metadata\Form as CustomerForm;
+use Magento\Framework\Api\ExtensibleDataObjectConverter;
 use Magento\Framework\App\ObjectManager;
 use Magento\Quote\Model\Quote\Address;
 use Magento\Quote\Model\Quote\Item;
+use Magento\Sales\Api\Data\OrderAddressInterface;
+use Magento\Sales\Model\Order;
 
 /**
  * Order create model
@@ -235,6 +238,11 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
      */
     private $serializer;
 
+    /**
+     * @var ExtensibleDataObjectConverter
+     */
+    private $dataObjectConverter;
+
     /**
      * @param \Magento\Framework\ObjectManagerInterface $objectManager
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
@@ -265,6 +273,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
      * @param \Magento\Quote\Model\QuoteFactory $quoteFactory
      * @param array $data
      * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+     * @param ExtensibleDataObjectConverter|null $dataObjectConverter
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -296,7 +305,8 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
         \Magento\Sales\Api\OrderManagementInterface $orderManagement,
         \Magento\Quote\Model\QuoteFactory $quoteFactory,
         array $data = [],
-        \Magento\Framework\Serialize\Serializer\Json $serializer = null
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null,
+        ExtensibleDataObjectConverter $dataObjectConverter = null
     ) {
         $this->_objectManager = $objectManager;
         $this->_eventManager = $eventManager;
@@ -328,6 +338,8 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
         $this->serializer = $serializer ?: ObjectManager::getInstance()
             ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct($data);
+        $this->dataObjectConverter = $dataObjectConverter ?: ObjectManager::getInstance()
+            ->get(ExtensibleDataObjectConverter::class);
     }
 
     /**
@@ -514,9 +526,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
 
         $shippingAddress = $order->getShippingAddress();
         if ($shippingAddress) {
-            $addressDiff = array_diff_assoc($shippingAddress->getData(), $order->getBillingAddress()->getData());
-            unset($addressDiff['address_type'], $addressDiff['entity_id']);
-            $shippingAddress->setSameAsBilling(empty($addressDiff));
+            $shippingAddress->setSameAsBilling($this->isAddressesAreEqual($order));
         }
 
         $this->_initBillingAddressFromOrder($order);
@@ -2010,4 +2020,26 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
 
         return $email;
     }
+
+    /**
+     * Checks id shipping and billing addresses are equal.
+     *
+     * @param Order $order
+     * @return bool
+     */
+    private function isAddressesAreEqual(Order $order)
+    {
+        $shippingAddress = $order->getShippingAddress();
+        $billingAddress = $order->getBillingAddress();
+        $shippingData = $this->dataObjectConverter->toFlatArray($shippingAddress, [], OrderAddressInterface::class);
+        $billingData = $this->dataObjectConverter->toFlatArray($billingAddress, [], OrderAddressInterface::class);
+        unset(
+            $shippingData['address_type'],
+            $shippingData['entity_id'],
+            $billingData['address_type'],
+            $billingData['entity_id']
+        );
+
+        return $shippingData == $billingData;
+    }
 }
diff --git a/app/code/Magento/Sales/Model/Service/CreditmemoService.php b/app/code/Magento/Sales/Model/Service/CreditmemoService.php
index 2f08c26de905878219b1c738d10c51be696367df..24f56c0dbd595215956cd9134f4e8ca23ecf194c 100644
--- a/app/code/Magento/Sales/Model/Service/CreditmemoService.php
+++ b/app/code/Magento/Sales/Model/Service/CreditmemoService.php
@@ -195,7 +195,7 @@ class CreditmemoService implements \Magento\Sales\Api\CreditmemoManagementInterf
      */
     protected function validateForRefund(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo)
     {
-        if ($creditmemo->getId()) {
+        if ($creditmemo->getId() && $creditmemo->getState() != \Magento\Sales\Model\Order\Creditmemo::STATE_OPEN) {
             throw new \Magento\Framework\Exception\LocalizedException(
                 __('We cannot register an existing credit memo.')
             );
diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php
index a265d39bafd931cbc94ddb7135cab1689cb9d4b7..b284a529d2a150132be62c141eee208997be94c4 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php
@@ -8,8 +8,25 @@
 
 namespace Magento\Sales\Test\Unit\Model\AdminOrder;
 
+use Magento\Backend\Model\Session\Quote as SessionQuote;
+use Magento\Customer\Api\Data\AttributeMetadataInterface;
+use Magento\Customer\Api\Data\CustomerInterface;
+use Magento\Customer\Api\Data\CustomerInterfaceFactory;
+use Magento\Customer\Api\Data\GroupInterface;
+use Magento\Customer\Api\GroupRepositoryInterface;
+use Magento\Customer\Model\Customer\Mapper;
+use Magento\Customer\Model\Metadata\Form;
+use Magento\Customer\Model\Metadata\FormFactory;
+use Magento\Framework\Api\DataObjectHelper;
+use Magento\Framework\App\RequestInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Quote\Model\Quote;
+use Magento\Quote\Model\Quote\Address;
+use Magento\Quote\Model\Quote\Item;
+use Magento\Quote\Model\Quote\Item\Updater;
+use Magento\Sales\Model\AdminOrder\Create;
 use Magento\Sales\Model\AdminOrder\Product;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -19,161 +36,74 @@ class CreateTest extends \PHPUnit\Framework\TestCase
 {
     const CUSTOMER_ID = 1;
 
-    /** @var \Magento\Sales\Model\AdminOrder\Create */
-    protected $adminOrderCreate;
-
-    /** @var \Magento\Backend\Model\Session\Quote|\PHPUnit_Framework_MockObject_MockObject */
-    protected $sessionQuoteMock;
-
-    /** @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject */
-    protected $formFactoryMock;
-
-    /** @var \Magento\Customer\Api\Data\CustomerInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject */
-    protected $customerFactoryMock;
-
-    /** @var \Magento\Quote\Model\Quote\Item\Updater|\PHPUnit_Framework_MockObject_MockObject */
-    protected $itemUpdater;
-
-    /** @var \Magento\Customer\Model\Customer\Mapper|\PHPUnit_Framework_MockObject_MockObject */
-    protected $customerMapper;
-
     /**
-     * @var Product\Quote\Initializer|\PHPUnit_Framework_MockObject_MockObject
+     * @var Create
      */
-    protected $quoteInitializerMock;
+    private $adminOrderCreate;
 
     /**
-     * @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var SessionQuote|MockObject
      */
-    protected $customerRepositoryMock;
+    private $sessionQuote;
 
     /**
-     * @var \Magento\Customer\Api\AddressRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var FormFactory|MockObject
      */
-    protected $addressRepositoryMock;
+    private $formFactory;
 
     /**
-     * @var \Magento\Customer\Api\Data\AddressInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
+     * @var CustomerInterfaceFactory|MockObject
      */
-    protected $addressFactoryMock;
+    private $customerFactory;
 
     /**
-     * @var \Magento\Customer\Api\GroupRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var Updater|MockObject
      */
-    protected $groupRepositoryMock;
+    private $itemUpdater;
 
     /**
-     * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var Mapper|MockObject
      */
-    protected $scopeConfigMock;
+    private $customerMapper;
 
     /**
-     * @var \Magento\Sales\Model\AdminOrder\EmailSender|\PHPUnit_Framework_MockObject_MockObject
+     * @var GroupRepositoryInterface|MockObject
      */
-    protected $emailSenderMock;
+    private $groupRepository;
 
     /**
-     * @var \Magento\Customer\Api\AccountManagementInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var DataObjectHelper|MockObject
      */
-    protected $accountManagementMock;
+    private $dataObjectHelper;
 
-    /**
-     * @var \Magento\Framework\Api\DataObjectHelper|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $dataObjectHelper;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $objectFactory;
-
-    /**
-     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
-     */
     protected function setUp()
     {
-        $objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
-        $eventManagerMock = $this->createMock(\Magento\Framework\Event\ManagerInterface::class);
-        $registryMock = $this->createMock(\Magento\Framework\Registry::class);
-        $configMock = $this->createMock(\Magento\Sales\Model\Config::class);
-        $this->sessionQuoteMock = $this->createMock(\Magento\Backend\Model\Session\Quote::class);
-        $loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class);
-        $copyMock = $this->createMock(\Magento\Framework\DataObject\Copy::class);
-        $messageManagerMock = $this->createMock(\Magento\Framework\Message\ManagerInterface::class);
-        $this->formFactoryMock = $this->createPartialMock(\Magento\Customer\Model\Metadata\FormFactory::class, ['create']);
-        $this->customerFactoryMock = $this->createPartialMock(\Magento\Customer\Api\Data\CustomerInterfaceFactory::class, ['create']);
-
-        $this->itemUpdater = $this->createMock(\Magento\Quote\Model\Quote\Item\Updater::class);
-
-        $this->objectFactory = $this->getMockBuilder(\Magento\Framework\DataObject\Factory::class)
+        $this->sessionQuote = $this->createMock(SessionQuote::class);
+        $this->formFactory = $this->createPartialMock(FormFactory::class, ['create']);
+        $this->customerFactory = $this->createPartialMock(CustomerInterfaceFactory::class, ['create']);
+
+        $this->itemUpdater = $this->createMock(Updater::class);
+
+        $this->customerMapper = $this->getMockBuilder(Mapper::class)
+            ->setMethods(['toFlatArray'])
             ->disableOriginalConstructor()
-            ->setMethods(['create'])
             ->getMock();
 
-        $this->customerMapper = $this->getMockBuilder(
-            \Magento\Customer\Model\Customer\Mapper::class
-        )->setMethods(['toFlatArray'])->disableOriginalConstructor()->getMock();
-
-        $this->quoteInitializerMock = $this->createMock(\Magento\Sales\Model\AdminOrder\Product\Quote\Initializer::class);
-        $this->customerRepositoryMock = $this->getMockForAbstractClass(
-            \Magento\Customer\Api\CustomerRepositoryInterface::class,
-            [],
-            '',
-            false
-        );
-        $this->addressRepositoryMock = $this->getMockForAbstractClass(
-            \Magento\Customer\Api\AddressRepositoryInterface::class,
-            [],
-            '',
-            false
-        );
-        $this->addressFactoryMock = $this->createMock(\Magento\Customer\Api\Data\AddressInterfaceFactory::class);
-        $this->groupRepositoryMock = $this->getMockForAbstractClass(
-            \Magento\Customer\Api\GroupRepositoryInterface::class,
-            [],
-            '',
-            false
-        );
-        $this->scopeConfigMock = $this->getMockForAbstractClass(
-            \Magento\Framework\App\Config\ScopeConfigInterface::class,
-            [],
-            '',
-            false
-        );
-        $this->emailSenderMock = $this->createMock(\Magento\Sales\Model\AdminOrder\EmailSender::class);
-        $this->accountManagementMock = $this->getMockForAbstractClass(
-            \Magento\Customer\Api\AccountManagementInterface::class,
-            [],
-            '',
-            false
-        );
-        $this->dataObjectHelper = $this->getMockBuilder(\Magento\Framework\Api\DataObjectHelper::class)
+        $this->groupRepository = $this->getMockForAbstractClass(GroupRepositoryInterface::class);
+        $this->dataObjectHelper = $this->getMockBuilder(DataObjectHelper::class)
             ->disableOriginalConstructor()
             ->getMock();
 
         $objectManagerHelper = new ObjectManagerHelper($this);
         $this->adminOrderCreate = $objectManagerHelper->getObject(
-            \Magento\Sales\Model\AdminOrder\Create::class,
+            Create::class,
             [
-                'objectManager' => $objectManagerMock,
-                'eventManager' => $eventManagerMock,
-                'coreRegistry' => $registryMock,
-                'salesConfig' => $configMock,
-                'quoteSession' => $this->sessionQuoteMock,
-                'logger' => $loggerMock,
-                'objectCopyService' => $copyMock,
-                'messageManager' => $messageManagerMock,
-                'quoteInitializer' => $this->quoteInitializerMock,
-                'customerRepository' => $this->customerRepositoryMock,
-                'addressRepository' => $this->addressRepositoryMock,
-                'addressFactory' => $this->addressFactoryMock,
-                'metadataFormFactory' => $this->formFactoryMock,
-                'customerFactory' => $this->customerFactoryMock,
-                'groupRepository' => $this->groupRepositoryMock,
+                'quoteSession' => $this->sessionQuote,
+                'metadataFormFactory' => $this->formFactory,
+                'customerFactory' => $this->customerFactory,
+                'groupRepository' => $this->groupRepository,
                 'quoteItemUpdater' => $this->itemUpdater,
                 'customerMapper' => $this->customerMapper,
-                'objectFactory' => $this->objectFactory,
-                'accountManagement' => $this->accountManagementMock,
                 'dataObjectHelper' => $this->dataObjectHelper,
             ]
         );
@@ -188,64 +118,60 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         ];
         $attributeMocks = [];
 
-        foreach ($attributes as $attribute) {
-            $attributeMock = $this->createMock(\Magento\Customer\Api\Data\AttributeMetadataInterface::class);
+        foreach ($attributes as $value) {
+            $attribute = $this->createMock(AttributeMetadataInterface::class);
+            $attribute->method('getAttributeCode')
+                ->willReturn($value[0]);
 
-            $attributeMock->expects($this->any())->method('getAttributeCode')->will($this->returnValue($attribute[0]));
-
-            $attributeMocks[] = $attributeMock;
+            $attributeMocks[] = $attribute;
         }
 
-        $customerGroupMock = $this->getMockForAbstractClass(
-            \Magento\Customer\Api\Data\GroupInterface::class,
-            [],
-            '',
-            false,
-            true,
-            true,
-            ['getTaxClassId']
-        );
-        $customerGroupMock->expects($this->once())->method('getTaxClassId')->will($this->returnValue($taxClassId));
-        $customerFormMock = $this->createMock(\Magento\Customer\Model\Metadata\Form::class);
-        $customerFormMock->expects($this->any())
-            ->method('getAttributes')
-            ->will($this->returnValue([$attributeMocks[1]]));
-        $customerFormMock->expects($this->any())->method('extractData')->will($this->returnValue([]));
-        $customerFormMock->expects($this->any())->method('restoreData')->will($this->returnValue(['group_id' => 1]));
-
-        $customerFormMock->expects($this->any())
-            ->method('prepareRequest')
-            ->will($this->returnValue($this->createMock(\Magento\Framework\App\RequestInterface::class)));
-
-        $customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class);
-        $this->customerMapper->expects($this->atLeastOnce())
+        $customerGroup = $this->getMockForAbstractClass(GroupInterface::class);
+        $customerGroup->method('getTaxClassId')
+            ->willReturn($taxClassId);
+        $customerForm = $this->createMock(Form::class);
+        $customerForm->method('getAttributes')
+            ->willReturn([$attributeMocks[1]]);
+        $customerForm
+            ->method('extractData')
+            ->willReturn([]);
+        $customerForm
+            ->method('restoreData')
+            ->willReturn(['group_id' => 1]);
+
+        $customerForm->method('prepareRequest')
+            ->willReturn($this->createMock(RequestInterface::class));
+
+        $customer = $this->createMock(CustomerInterface::class);
+        $this->customerMapper->expects(self::atLeastOnce())
             ->method('toFlatArray')
             ->willReturn(['group_id' => 1]);
 
-        $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
-        $quoteMock->expects($this->any())->method('getCustomer')->will($this->returnValue($customerMock));
-        $quoteMock->expects($this->once())
-            ->method('addData')
+        $quote = $this->createMock(Quote::class);
+        $quote->method('getCustomer')->willReturn($customer);
+        $quote->method('addData')
             ->with(
             [
                 'customer_group_id' => $attributes[1][1],
                 'customer_tax_class_id' => $taxClassId
             ]
         );
-        $this->dataObjectHelper->expects($this->once())
-            ->method('populateWithArray')
+        $this->dataObjectHelper->method('populateWithArray')
             ->with(
-                $customerMock,
-                ['group_id' => 1], \Magento\Customer\Api\Data\CustomerInterface::class
+                $customer,
+                ['group_id' => 1], CustomerInterface::class
             );
 
-        $this->formFactoryMock->expects($this->any())->method('create')->will($this->returnValue($customerFormMock));
-        $this->sessionQuoteMock->expects($this->any())->method('getQuote')->will($this->returnValue($quoteMock));
-        $this->customerFactoryMock->expects($this->any())->method('create')->will($this->returnValue($customerMock));
+        $this->formFactory->method('create')
+            ->willReturn($customerForm);
+        $this->sessionQuote
+            ->method('getQuote')
+            ->willReturn($quote);
+        $this->customerFactory->method('create')
+            ->willReturn($customer);
 
-        $this->groupRepositoryMock->expects($this->once())
-            ->method('getById')
-            ->will($this->returnValue($customerGroupMock));
+        $this->groupRepository->method('getById')
+            ->willReturn($customerGroup);
 
         $this->adminOrderCreate->setAccountData(['group_id' => 1]);
     }
@@ -253,7 +179,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
     public function testUpdateQuoteItemsNotArray()
     {
         $object = $this->adminOrderCreate->updateQuoteItems('string');
-        $this->assertEquals($this->adminOrderCreate, $object);
+        self::assertEquals($this->adminOrderCreate, $object);
     }
 
     public function testUpdateQuoteItemsEmptyConfiguredOption()
@@ -266,22 +192,21 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             ]
         ];
 
-        $itemMock = $this->createMock(\Magento\Quote\Model\Quote\Item::class);
+        $item = $this->createMock(Item::class);
 
-        $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
-        $quoteMock->expects($this->once())
-            ->method('getItemById')
-            ->will($this->returnValue($itemMock));
+        $quote = $this->createMock(Quote::class);
+        $quote->method('getItemById')
+            ->willReturn($item);
 
-        $this->sessionQuoteMock->expects($this->any())->method('getQuote')->will($this->returnValue($quoteMock));
-        $this->itemUpdater->expects($this->once())
-            ->method('update')
-            ->with($this->equalTo($itemMock), $this->equalTo($items[1]))
-            ->will($this->returnSelf());
+        $this->sessionQuote->method('getQuote')
+            ->willReturn($quote);
+        $this->itemUpdater->method('update')
+            ->with(self::equalTo($item), self::equalTo($items[1]))
+            ->willReturnSelf();
 
         $this->adminOrderCreate->setRecollect(false);
         $object = $this->adminOrderCreate->updateQuoteItems($items);
-        $this->assertEquals($this->adminOrderCreate, $object);
+        self::assertEquals($this->adminOrderCreate, $object);
     }
 
     public function testUpdateQuoteItemsWithConfiguredOption()
@@ -295,43 +220,50 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             ]
         ];
 
-        $itemMock = $this->createMock(\Magento\Quote\Model\Quote\Item::class);
-        $itemMock->expects($this->once())
-            ->method('getQty')
-            ->will($this->returnValue($qty));
+        $item = $this->createMock(Item::class);
+        $item->method('getQty')
+            ->willReturn($qty);
 
-        $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
-        $quoteMock->expects($this->once())
-            ->method('updateItem')
-            ->will($this->returnValue($itemMock));
+        $quote = $this->createMock(Quote::class);
+        $quote->method('updateItem')
+            ->willReturn($item);
 
-        $this->sessionQuoteMock->expects($this->any())->method('getQuote')->will($this->returnValue($quoteMock));
+        $this->sessionQuote
+            ->method('getQuote')
+            ->willReturn($quote);
 
         $expectedInfo = $items[1];
         $expectedInfo['qty'] = $qty;
-        $this->itemUpdater->expects($this->once())
-            ->method('update')
-            ->with($this->equalTo($itemMock), $this->equalTo($expectedInfo));
+        $this->itemUpdater->method('update')
+            ->with(self::equalTo($item), self::equalTo($expectedInfo));
 
         $this->adminOrderCreate->setRecollect(false);
         $object = $this->adminOrderCreate->updateQuoteItems($items);
-        $this->assertEquals($this->adminOrderCreate, $object);
+        self::assertEquals($this->adminOrderCreate, $object);
     }
 
     public function testApplyCoupon()
     {
-        $couponCode = '';
-        $quoteMock = $this->createPartialMock(\Magento\Quote\Model\Quote::class, ['getShippingAddress', 'setCouponCode']);
-        $this->sessionQuoteMock->expects($this->once())->method('getQuote')->willReturn($quoteMock);
-
-        $addressMock = $this->createPartialMock(\Magento\Quote\Model\Quote\Address::class, ['setCollectShippingRates', 'setFreeShipping']);
-        $quoteMock->expects($this->exactly(2))->method('getShippingAddress')->willReturn($addressMock);
-        $quoteMock->expects($this->once())->method('setCouponCode')->with($couponCode)->willReturnSelf();
-
-        $addressMock->expects($this->once())->method('setCollectShippingRates')->with(true)->willReturnSelf();
-        $addressMock->expects($this->once())->method('setFreeShipping')->with(0)->willReturnSelf();
+        $couponCode = '123';
+        $quote = $this->createPartialMock(Quote::class, ['getShippingAddress', 'setCouponCode']);
+        $this->sessionQuote->method('getQuote')
+            ->willReturn($quote);
+
+        $address = $this->createPartialMock(Address::class, ['setCollectShippingRates', 'setFreeShipping']);
+        $quote->method('getShippingAddress')
+            ->willReturn($address);
+        $quote->method('setCouponCode')
+            ->with($couponCode)
+            ->willReturnSelf();
+
+        $address->method('setCollectShippingRates')
+            ->with(true)
+            ->willReturnSelf();
+        $address->method('setFreeShipping')
+            ->with(0)
+            ->willReturnSelf();
 
         $object = $this->adminOrderCreate->applyCoupon($couponCode);
-        $this->assertEquals($this->adminOrderCreate, $object);
+        self::assertEquals($this->adminOrderCreate, $object);
     }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Service/CreditmemoServiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/Service/CreditmemoServiceTest.php
index 9ecab6cf9ab52d76b80d4c195c7e00608db187ec..2e668f0b0d6f114ce3adb6efc14d2292c16b4cd2 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Service/CreditmemoServiceTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Service/CreditmemoServiceTest.php
@@ -243,6 +243,78 @@ class CreditmemoServiceTest extends \PHPUnit\Framework\TestCase
         $this->assertSame($creditMemoMock, $this->creditmemoService->refund($creditMemoMock, true));
     }
 
+    public function testRefundPendingCreditMemo()
+    {
+        $creditMemoMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoInterface::class)
+            ->setMethods(['getId', 'getOrder', 'getState', 'getInvoice'])
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditMemoMock->expects($this->once())->method('getId')->willReturn(444);
+        $creditMemoMock->expects($this->once())->method('getState')
+            ->willReturn(\Magento\Sales\Model\Order\Creditmemo::STATE_OPEN);
+        $orderMock = $this->getMockBuilder(Order::class)->disableOriginalConstructor()->getMock();
+
+        $creditMemoMock->expects($this->atLeastOnce())->method('getOrder')->willReturn($orderMock);
+        $orderMock->expects($this->once())->method('getBaseTotalRefunded')->willReturn(0);
+        $orderMock->expects($this->once())->method('getBaseTotalPaid')->willReturn(10);
+        $creditMemoMock->expects($this->once())->method('getBaseGrandTotal')->willReturn(10);
+
+        $this->priceCurrencyMock->expects($this->any())
+            ->method('round')
+            ->willReturnArgument(0);
+
+        // Set payment adapter dependency
+        $refundAdapterMock = $this->getMockBuilder(\Magento\Sales\Model\Order\RefundAdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->objectManagerHelper->setBackwardCompatibleProperty(
+            $this->creditmemoService,
+            'refundAdapter',
+            $refundAdapterMock
+        );
+
+        // Set resource dependency
+        $resourceMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->objectManagerHelper->setBackwardCompatibleProperty(
+            $this->creditmemoService,
+            'resource',
+            $resourceMock
+        );
+
+        // Set order repository dependency
+        $orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->objectManagerHelper->setBackwardCompatibleProperty(
+            $this->creditmemoService,
+            'orderRepository',
+            $orderRepositoryMock
+        );
+
+        $adapterMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $resourceMock->expects($this->once())->method('getConnection')->with('sales')->willReturn($adapterMock);
+        $adapterMock->expects($this->once())->method('beginTransaction');
+        $refundAdapterMock->expects($this->once())
+            ->method('refund')
+            ->with($creditMemoMock, $orderMock, false)
+            ->willReturn($orderMock);
+        $orderRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($orderMock);
+        $creditMemoMock->expects($this->once())
+            ->method('getInvoice')
+            ->willReturn(null);
+        $adapterMock->expects($this->once())->method('commit');
+        $this->creditmemoRepositoryMock->expects($this->once())
+            ->method('save');
+
+        $this->assertSame($creditMemoMock, $this->creditmemoService->refund($creditMemoMock, true));
+    }
+
     /**
      * @expectedExceptionMessage The most money available to refund is 1.
      * @expectedException \Magento\Framework\Exception\LocalizedException
diff --git a/app/code/Magento/Sitemap/Model/Observer.php b/app/code/Magento/Sitemap/Model/Observer.php
index 3ae3061310a0b24a76b7bc2c410cc64c156c7ecf..840a6a1858fae5974db7f2e908b13213780dd2c2 100644
--- a/app/code/Magento/Sitemap/Model/Observer.php
+++ b/app/code/Magento/Sitemap/Model/Observer.php
@@ -113,7 +113,6 @@ class Observer
                 $sitemap->generateXml();
             } catch (\Exception $e) {
                 $errors[] = $e->getMessage();
-                throw $e;
             }
         }
 
@@ -122,8 +121,7 @@ class Observer
             \Magento\Store\Model\ScopeInterface::SCOPE_STORE
         )
         ) {
-            $translate = $this->_translateModel->getTranslateInline();
-            $this->_translateModel->setTranslateInline(false);
+            $this->inlineTranslation->suspend();
 
             $this->_transportBuilder->setTemplateIdentifier(
                 $this->_scopeConfig->getValue(
diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php
index 92e6f4e2e2293d2b6b3e31058732df7d70810cd5..ac88f23ff9d6977f086df62cb84927f027c1eada 100644
--- a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php
+++ b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php
@@ -7,6 +7,10 @@ namespace Magento\Sitemap\Test\Unit\Model;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
+/**
+ * Class ObserverTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class ObserverTest extends \PHPUnit\Framework\TestCase
 {
     /**
@@ -96,11 +100,11 @@ class ObserverTest extends \PHPUnit\Framework\TestCase
         );
     }
 
-    /**
-     * @expectedException \Exception
-     */
-    public function testScheduledGenerateSitemapsThrowsException()
+    public function testScheduledGenerateSitemapsSendsExceptionEmail()
     {
+        $exception = 'Sitemap Exception';
+        $transport = $this->createMock(\Magento\Framework\Mail\TransportInterface::class);
+
         $this->scopeConfigMock->expects($this->once())->method('isSetFlag')->willReturn(true);
 
         $this->collectionFactoryMock->expects($this->once())
@@ -111,7 +115,55 @@ class ObserverTest extends \PHPUnit\Framework\TestCase
             ->method('getIterator')
             ->willReturn(new \ArrayIterator([$this->sitemapMock]));
 
-        $this->sitemapMock->expects($this->once())->method('generateXml')->willThrowException(new \Exception());
+        $this->sitemapMock->expects($this->once())
+            ->method('generateXml')
+            ->willThrowException(new \Exception($exception));
+
+        $this->scopeConfigMock->expects($this->at(1))
+            ->method('getValue')
+            ->with(
+                \Magento\Sitemap\Model\Observer::XML_PATH_ERROR_RECIPIENT,
+                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+            )
+            ->willReturn('error-recipient@example.com');
+
+        $this->inlineTranslationMock->expects($this->once())
+            ->method('suspend');
+
+        $this->transportBuilderMock->expects($this->once())
+            ->method('setTemplateIdentifier')
+            ->will($this->returnSelf());
+
+        $this->transportBuilderMock->expects($this->once())
+            ->method('setTemplateOptions')
+            ->with([
+                'area' => \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE,
+                'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
+            ])
+            ->will($this->returnSelf());
+
+        $this->transportBuilderMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(['warnings' => $exception])
+            ->will($this->returnSelf());
+
+        $this->transportBuilderMock->expects($this->once())
+            ->method('setFrom')
+            ->will($this->returnSelf());
+
+        $this->transportBuilderMock->expects($this->once())
+            ->method('addTo')
+            ->will($this->returnSelf());
+
+        $this->transportBuilderMock->expects($this->once())
+            ->method('getTransport')
+            ->willReturn($transport);
+
+        $transport->expects($this->once())
+            ->method('sendMessage');
+
+        $this->inlineTranslationMock->expects($this->once())
+            ->method('resume');
 
         $this->observer->scheduledGenerateSitemaps();
     }
diff --git a/app/code/Magento/Tax/Model/Plugin/OrderSave.php b/app/code/Magento/Tax/Model/Plugin/OrderSave.php
index 3c87086cdf585b285fbe49fda23912c167851c26..a1a3ebf861d60f9fa4e07dc02714bb59594b2b83 100644
--- a/app/code/Magento/Tax/Model/Plugin/OrderSave.php
+++ b/app/code/Magento/Tax/Model/Plugin/OrderSave.php
@@ -97,8 +97,12 @@ class OrderSave
                         } else {
                             $percentSum = 0;
                             foreach ($taxRates as $rate) {
-                                $realAmount = $rates['amount'] * $rate['percent'] / $rates['percent'];
-                                $realBaseAmount = $rates['base_amount'] * $rate['percent'] / $rates['percent'];
+                                $percentSum += $rate['percent'];
+                            }
+
+                            foreach ($taxRates as $rate) {
+                                $realAmount = $rates['amount'] * $rate['percent'] / $percentSum;
+                                $realBaseAmount = $rates['base_amount'] * $rate['percent'] / $percentSum;
                                 $ratesIdQuoteItemId[$rates['id']][] = [
                                     'id' => $taxesArray['item_id'],
                                     'percent' => $rate['percent'],
@@ -110,7 +114,6 @@ class OrderSave
                                     'real_amount' => $realAmount,
                                     'real_base_amount' => $realBaseAmount,
                                 ];
-                                $percentSum += $rate['percent'];
                             }
                         }
                     }
diff --git a/app/design/frontend/Magento/luma/Magento_Email/email/footer.html b/app/design/frontend/Magento/luma/Magento_Email/email/footer.html
index 994f9e6bffed8dea3f682fdb4d8a92a8aaf3f50d..0fc8e36a8207672e44fb00b63d2d2050665540dc 100644
--- a/app/design/frontend/Magento/luma/Magento_Email/email/footer.html
+++ b/app/design/frontend/Magento/luma/Magento_Email/email/footer.html
@@ -17,8 +17,16 @@
                         <table>
                             <tr>
                                 <td>
-                                    <p><a href="#">{{trans "About Us"}}</a></p>
-                                    <p><a href="#">{{trans "Customer Service"}}</a></p>
+                                    {{depend url_about_us}}
+                                    <p>
+                                        {{trans '<a href=%url_about_us>About Us</a>' url_about_us=$url_about_us |raw}}
+                                    </p>
+                                    {{/depend}}
+                                    {{depend url_customer_service}}
+                                    <p>
+                                        {{trans '<a href=url_customer_service>Customer Service</a>' url_customer_service=$url_customer_service |raw}}
+                                    </p>
+                                    {{/depend}}
                                 </td>
                                 <td>
                                     {{depend store_phone}}
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductGettersTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductGettersTest.php
index 74f640a021284eec3c90254d57fad52cd6483eb4..1ed0057ca2486512a43bed5d0baf4dac1f8cf2d5 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductGettersTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductGettersTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Catalog\Model;
 
+use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\Framework\App\Filesystem\DirectoryList;
 
 /**
@@ -25,11 +26,19 @@ class ProductGettersTest extends \PHPUnit\Framework\TestCase
      */
     protected $_model;
 
+    /**
+     * @var ProductRepositoryInterface
+     */
+    private $productRepository;
+
     protected function setUp()
     {
         $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
             \Magento\Catalog\Model\Product::class
         );
+        $this->productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            ProductRepositoryInterface::class
+        );
     }
 
     public function testGetResourceCollection()
@@ -198,6 +207,24 @@ class ProductGettersTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals('Enabled', $this->_model->getAttributeText('status'));
     }
 
+    /**
+     * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php
+     */
+    public function testGetAttributeTextArray()
+    {
+        $product = $this->productRepository->get('simple_ms_2');
+        $product->getAttributeText('multiselect_attribute');
+        $expected = [
+            'Option 2',
+            'Option 3',
+            'Option 4 "!@#$%^&*'
+        ];
+        self::assertEquals(
+            $expected,
+            $product->getAttributeText('multiselect_attribute')
+        );
+    }
+
     public function testGetCustomDesignDate()
     {
         $this->assertEquals(['from' => null, 'to' => null], $this->_model->getCustomDesignDate());
diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/CurrencyConfigTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/CurrencyConfigTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b620d9097b4befcc634d1ad4235129f632c66c5d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Directory/Model/CurrencyConfigTest.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Directory\Model;
+
+use Magento\Directory\Model\Currency as CurrencyModel;
+use Magento\Framework\App\Area;
+use Magento\Framework\App\Config\ConfigResource\ConfigInterface;
+use Magento\Framework\App\Config\ReinitableConfigInterface;
+use Magento\Store\Model\Store;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\TestFramework\App\State;
+use Magento\TestFramework\Helper\Bootstrap;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Provide tests for CurrencyConfig model.
+ */
+class CurrencyConfigTest extends TestCase
+{
+    /**
+     * @var string
+     */
+    private $baseCurrencyPath = 'currency/options/base';
+
+    /**
+     * @var string
+     */
+    private $defaultCurrencyPath = 'currency/options/default';
+
+    /**
+     * @var string
+     */
+    private $allowedCurrenciesPath = 'currency/options/allow';
+
+    /**
+     * @var ConfigInterface
+     */
+    private $config;
+
+    /**
+     * @var CurrencyModel
+     */
+    private $currency;
+
+    /**
+     * @inheritdoc
+     */
+    protected function setUp()
+    {
+        $this->currency = Bootstrap::getObjectManager()->get(CurrencyModel::class);
+        $this->config = Bootstrap::getObjectManager()->get(ConfigInterface::class);
+    }
+
+    /**
+     * Test get currency config for admin and storefront areas.
+     *
+     * @dataProvider getConfigCurrenciesDataProvider
+     * @magentoDataFixture Magento/Store/_files/store.php
+     * @magentoDbIsolation disabled
+     * @param string $areaCode
+     * @param array $expected
+     * @return void
+     */
+    public function testGetConfigCurrencies(string $areaCode, array $expected)
+    {
+        /** @var State $appState */
+        $appState = Bootstrap::getObjectManager()->get(State::class);
+        $appState->setAreaCode($areaCode);
+        $store = Bootstrap::getObjectManager()->get(Store::class);
+        $store->load('test', 'code');
+        $this->clearCurrencyConfig();
+        $this->setStoreConfig($store->getId());
+        $storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
+        $storeManager->setCurrentStore($store->getId());
+
+        if ($areaCode === Area::AREA_ADMINHTML) {
+            self::assertEquals($expected['allowed'], $this->currency->getConfigAllowCurrencies());
+            self::assertEquals($expected['base'], $this->currency->getConfigBaseCurrencies());
+            self::assertEquals($expected['default'], $this->currency->getConfigDefaultCurrencies());
+        } else {
+            /** @var StoreManagerInterface $storeManager */
+            $storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
+            foreach ($storeManager->getStores() as $store) {
+                $storeManager->setCurrentStore($store->getId());
+                self::assertEquals(
+                    $expected[$store->getCode()]['allowed'],
+                    $this->currency->getConfigAllowCurrencies()
+                );
+                self::assertEquals(
+                    $expected[$store->getCode()]['base'],
+                    $this->currency->getConfigBaseCurrencies()
+                );
+                self::assertEquals(
+                    $expected[$store->getCode()]['default'],
+                    $this->currency->getConfigDefaultCurrencies()
+                );
+            }
+        }
+    }
+
+    /**
+     * Provide test data for getConfigCurrencies test.
+     *
+     * @return array
+     */
+    public function getConfigCurrenciesDataProvider()
+    {
+        return [
+            [
+                'areaCode' => Area::AREA_ADMINHTML,
+                'expected' => [
+                    'allowed' => ['BDT', 'BNS', 'BTD', 'EUR', 'USD'],
+                    'base' => ['BDT', 'USD'],
+                    'default' => ['BDT', 'USD'],
+                ],
+            ],
+            [
+                'areaCode' => Area::AREA_FRONTEND,
+                'expected' => [
+                    'default' => [
+                        'allowed' => ['EUR', 'USD'],
+                        'base' => ['USD'],
+                        'default' => ['USD'],
+                    ],
+                    'test' => [
+                        'allowed' => ['BDT', 'BNS', 'BTD', 'USD'],
+                        'base' => ['BDT'],
+                        'default' => ['BDT'],
+                    ],
+                ],
+            ],
+        ];
+    }
+
+    /**
+     * Remove currency config form Db.
+     *
+     * @return void
+     */
+    private function clearCurrencyConfig()
+    {
+        $storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
+        foreach ($storeManager->getStores() as $store) {
+            $this->config->deleteConfig(
+                $this->allowedCurrenciesPath,
+                'stores',
+                $store->getId()
+            );
+            $this->config->deleteConfig(
+                $this->baseCurrencyPath,
+                'stores',
+                $store->getId()
+            );
+            $this->config->deleteConfig(
+                $this->defaultCurrencyPath,
+                'stores',
+                $store->getId()
+            );
+        }
+    }
+
+    /**
+     * Set allowed, base and default currency config values for given store.
+     *
+     * @param string $storeId
+     * @return void
+     */
+    private function setStoreConfig(string $storeId)
+    {
+        $allowedCurrencies = 'BDT,BNS,BTD';
+        $baseCurrency = 'BDT';
+        $this->config->saveConfig(
+            $this->baseCurrencyPath,
+            $baseCurrency,
+            'stores',
+            $storeId
+        );
+        $this->config->saveConfig(
+            $this->defaultCurrencyPath,
+            $baseCurrency,
+            'stores',
+            $storeId
+        );
+        $this->config->saveConfig(
+            $this->allowedCurrenciesPath,
+            $allowedCurrencies,
+            'stores',
+            $storeId
+        );
+        Bootstrap::getObjectManager()->get(ReinitableConfigInterface::class)->reinit();
+        Bootstrap::getObjectManager()->create(StoreManagerInterface::class)->reinitStores();
+    }
+
+    protected function tearDown()
+    {
+        $this->clearCurrencyConfig();
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
index ee7ddc1ba1abae57bb4daf4446e7be1f35ac30b3..408cc8d192e3749944dbc7e17b8c1a529a486811 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
@@ -5,10 +5,20 @@
  */
 namespace Magento\Sales\Model\AdminOrder;
 
+use Magento\Backend\Model\Session\Quote as SessionQuote;
+use Magento\Customer\Api\AddressRepositoryInterface;
+use Magento\Customer\Api\CustomerRepositoryInterface;
+use Magento\Customer\Model\Customer;
+use Magento\Customer\Model\CustomerRegistry;
+use Magento\Framework\Message\ManagerInterface;
+use Magento\Framework\Registry;
+use Magento\Quote\Model\Quote;
+use Magento\Sales\Api\Data\OrderAddressExtensionInterface;
+use Magento\Sales\Api\Data\OrderAddressExtensionInterfaceFactory;
 use Magento\Sales\Api\OrderManagementInterface;
-use Magento\TestFramework\Helper\Bootstrap;
 use Magento\Sales\Model\Order;
-use Magento\Framework\Registry;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\TestFramework\ObjectManager;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -18,21 +28,25 @@ use Magento\Framework\Registry;
 class CreateTest extends \PHPUnit\Framework\TestCase
 {
     /**
-     * @var \Magento\Sales\Model\AdminOrder\Create
+     * @var Create
      */
-    protected $_model;
+    private $model;
 
-    /** @var \Magento\Framework\Message\ManagerInterface */
-    protected $_messageManager;
+    /**
+     * @var ManagerInterface
+     */
+    private $messageManager;
+
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
 
     protected function setUp()
     {
-        parent::setUp();
-        $this->_messageManager = Bootstrap::getObjectManager()->get(\Magento\Framework\Message\ManagerInterface::class);
-        $this->_model = Bootstrap::getObjectManager()->create(
-            \Magento\Sales\Model\AdminOrder\Create::class,
-            ['messageManager' => $this->_messageManager]
-        );
+        $this->objectManager = Bootstrap::getObjectManager();
+        $this->messageManager = $this->objectManager->get(ManagerInterface::class);
+        $this->model =$this->objectManager->create(Create::class, ['messageManager' => $this->messageManager]);
     }
 
     /**
@@ -41,17 +55,15 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testInitFromOrderShippingAddressSameAsBillingWhenEmpty()
     {
-        /** @var $order \Magento\Sales\Model\Order */
-        $order = Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class);
+        /** @var $order Order */
+        $order = $this->objectManager->create(Order::class);
         $order->loadByIncrementId('100000001');
-        $this->assertNull($order->getShippingAddress());
+        self::assertNull($order->getShippingAddress());
 
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = Bootstrap::getObjectManager();
-        $objectManager->get(\Magento\Framework\Registry::class)->unregister('rule_data');
-        $this->_model->initFromOrder($order);
+        $this->objectManager->get(Registry::class)->unregister('rule_data');
+        $this->model->initFromOrder($order);
 
-        $this->assertNull($order->getShippingAddress());
+        self::assertNull($order->getShippingAddress());
     }
 
     /**
@@ -64,45 +76,45 @@ class CreateTest extends \PHPUnit\Framework\TestCase
     public function testInitFromOrderAndCreateOrderFromQuoteWithAdditionalOptions()
     {
         /** @var $serializer \Magento\Framework\Serialize\Serializer\Json */
-        $serializer = Bootstrap::getObjectManager()->create(\Magento\Framework\Serialize\Serializer\Json::class);
+        $serializer = $this->objectManager->create(\Magento\Framework\Serialize\Serializer\Json::class);
 
-        /** @var $order \Magento\Sales\Model\Order */
-        $order = Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class);
+        /** @var $order Order */
+        $order = $this->objectManager->create(Order::class);
         $order->loadByIncrementId('100000001');
 
         /** @var $orderCreate \Magento\Sales\Model\AdminOrder\Create */
-        $orderCreate = $this->_model->initFromOrder($order);
+        $orderCreate = $this->model->initFromOrder($order);
 
         $quoteItems = $orderCreate->getQuote()->getItemsCollection();
 
-        $this->assertEquals(1, $quoteItems->count());
+        self::assertEquals(1, $quoteItems->count());
 
         $quoteItem = $quoteItems->getFirstItem();
         $quoteItemOptions = $quoteItem->getOptionsByCode();
 
-        $this->assertEquals(
+        self::assertEquals(
             $serializer->serialize(['additional_option_key' => 'additional_option_value']),
             $quoteItemOptions['additional_options']->getValue()
         );
 
-        $session = Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session\Quote::class);
+        $session = $this->objectManager->get(SessionQuote::class);
         $session->setCustomerId(1);
 
-        $customer = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Customer::class);
+        $customer = $this->objectManager->create(Customer::class);
         $customer->load(1)->setDefaultBilling(null)->setDefaultShipping(null)->save();
 
-        $rate = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote\Address\Rate::class);
+        $rate = $this->objectManager->create(Quote\Address\Rate::class);
         $rate->setCode('freeshipping_freeshipping');
 
-        $this->_model->getQuote()->getShippingAddress()->addShippingRate($rate);
-        $this->_model->getQuote()->getShippingAddress()->setCountryId('EE');
-        $this->_model->setShippingAsBilling(0);
-        $this->_model->setPaymentData(['method' => 'checkmo']);
+        $this->model->getQuote()->getShippingAddress()->addShippingRate($rate);
+        $this->model->getQuote()->getShippingAddress()->setCountryId('EE');
+        $this->model->setShippingAsBilling(0);
+        $this->model->setPaymentData(['method' => 'checkmo']);
 
-        $newOrder = $this->_model->createOrder();
+        $newOrder = $this->model->createOrder();
         $newOrderItems = $newOrder->getItemsCollection();
 
-        $this->assertEquals(1, $newOrderItems->count());
+        self::assertEquals(1, $newOrderItems->count());
 
         $order->loadByIncrementId('100000001');
         $this->assertEquals($newOrder->getRealOrderId(), $order->getRelationChildRealId());
@@ -110,7 +122,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
 
         $newOrderItem = $newOrderItems->getFirstItem();
 
-        $this->assertEquals(
+        self::assertEquals(
             ['additional_option_key' => 'additional_option_value'],
             $newOrderItem->getProductOptionByCode('additional_options')
         );
@@ -123,18 +135,28 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testInitFromOrderShippingAddressSameAsBillingWhenSame()
     {
-        /** @var $order \Magento\Sales\Model\Order */
-        $order = Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class);
+        /** @var $order Order */
+        $order = $this->objectManager->create(Order::class);
         $order->loadByIncrementId('100000001');
 
-        $this->assertNull($order->getShippingAddress()->getSameAsBilling());
+        self::assertNull($order->getShippingAddress()->getSameAsBilling());
+
+        /** @var OrderAddressExtensionInterface $shippingExtAttributes */
+        $shippingExtAttributes = $this->objectManager->get(OrderAddressExtensionInterfaceFactory::class)
+            ->create();
 
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = Bootstrap::getObjectManager();
-        $objectManager->get(\Magento\Framework\Registry::class)->unregister('rule_data');
-        $this->_model->initFromOrder($order);
+        $billingExtAttributes = clone $shippingExtAttributes;
 
-        $this->assertTrue($order->getShippingAddress()->getSameAsBilling());
+        $shippingExtAttributes->setData('tmp', false);
+        $billingExtAttributes->setData('tmp', true);
+
+        $order->getShippingAddress()->setExtensionAttributes($shippingExtAttributes);
+        $order->getBillingAddress()->setExtensionAttributes($billingExtAttributes);
+
+        $this->objectManager->get(Registry::class)->unregister('rule_data');
+        $this->model->initFromOrder($order);
+
+        self::assertTrue($order->getShippingAddress()->getSameAsBilling());
     }
 
     /**
@@ -144,19 +166,16 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testInitFromOrderShippingAddressSameAsBillingWhenDifferent()
     {
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = Bootstrap::getObjectManager();
-
-        /** @var $order \Magento\Sales\Model\Order */
-        $order = $objectManager->create(\Magento\Sales\Model\Order::class);
+        /** @var $order Order */
+        $order = $this->objectManager->create(Order::class);
         $order->loadByIncrementId('100000002');
 
-        $this->assertNull($order->getShippingAddress()->getSameAsBilling());
+        self::assertNull($order->getShippingAddress()->getSameAsBilling());
 
-        $objectManager->get(\Magento\Framework\Registry::class)->unregister('rule_data');
-        $this->_model->initFromOrder($order);
+        $this->objectManager->get(Registry::class)->unregister('rule_data');
+        $this->model->initFromOrder($order);
 
-        $this->assertFalse($order->getShippingAddress()->getSameAsBilling());
+        self::assertFalse($order->getShippingAddress()->getSameAsBilling());
     }
 
     /**
@@ -164,26 +183,23 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testInitFromOrderCcInformationDeleted()
     {
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = Bootstrap::getObjectManager();
-
-        /** @var $order \Magento\Sales\Model\Order */
-        $order = $objectManager->create(\Magento\Sales\Model\Order::class);
+        /** @var $order Order */
+        $order = $this->objectManager->create(Order::class);
         $order->loadByIncrementId('100000001');
 
         $payment = $order->getPayment();
-        $this->assertEquals('5', $payment->getCcExpMonth());
-        $this->assertEquals('2016', $payment->getCcExpYear());
-        $this->assertEquals('AE', $payment->getCcType());
-        $this->assertEquals('0005', $payment->getCcLast4());
-
-        $objectManager->get(\Magento\Framework\Registry::class)->unregister('rule_data');
-        $payment = $this->_model->initFromOrder($order)->getQuote()->getPayment();
-
-        $this->assertNull($payment->getCcExpMonth());
-        $this->assertNull($payment->getCcExpYear());
-        $this->assertNull($payment->getCcType());
-        $this->assertNull($payment->getCcLast4());
+        self::assertEquals('5', $payment->getCcExpMonth());
+        self::assertEquals('2016', $payment->getCcExpYear());
+        self::assertEquals('AE', $payment->getCcType());
+        self::assertEquals('0005', $payment->getCcLast4());
+
+        $this->objectManager->get(Registry::class)->unregister('rule_data');
+        $payment = $this->model->initFromOrder($order)->getQuote()->getPayment();
+
+        self::assertNull($payment->getCcExpMonth());
+        self::assertNull($payment->getCcExpYear());
+        self::assertNull($payment->getCcType());
+        self::assertNull($payment->getCcLast4());
     }
 
     /**
@@ -191,25 +207,23 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testInitFromOrderWithEmptyPaymentDetails()
     {
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = Bootstrap::getObjectManager();
-        /** @var $order \Magento\Sales\Model\Order */
-        $order = $objectManager->create(Order::class);
+        /** @var $order Order */
+        $order = $this->objectManager->create(Order::class);
         $order->loadByIncrementId('100000001');
 
-        $objectManager->get(Registry::class)
+        $this->objectManager->get(Registry::class)
             ->unregister('rule_data');
 
-        $initOrder = $this->_model->initFromOrder($order);
+        $initOrder = $this->model->initFromOrder($order);
         $payment = $initOrder->getQuote()->getPayment();
 
-        static::assertEquals($initOrder->getQuote()->getId(), $payment->getData('quote_id'));
+        self::assertEquals($initOrder->getQuote()->getId(), $payment->getData('quote_id'));
         $payment->unsetData('quote_id');
 
-        static::assertEmpty($payment->getMethod());
-        static::assertEmpty($payment->getAdditionalInformation());
-        static::assertEmpty($payment->getAdditionalData());
-        static::assertEmpty($payment->getData());
+        self::assertEmpty($payment->getMethod());
+        self::assertEmpty($payment->getAdditionalInformation());
+        self::assertEmpty($payment->getAdditionalData());
+        self::assertEmpty($payment->getData());
     }
 
     /**
@@ -217,11 +231,11 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetCustomerWishlistNoCustomerId()
     {
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->create(SessionQuote::class);
         $session->setCustomerId(null);
-        $this->assertFalse(
-            $this->_model->getCustomerWishlist(true),
+        self::assertFalse(
+            $this->model->getCustomerWishlist(true),
             'If customer ID is not set to session, false is expected to be returned.'
         );
     }
@@ -236,24 +250,24 @@ class CreateTest extends \PHPUnit\Framework\TestCase
     {
         $customerIdFromFixture = 1;
         $productIdFromFixture = 1;
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->create(SessionQuote::class);
         $session->setCustomerId($customerIdFromFixture);
 
         /** Test new wishlist creation for the customer specified above */
         /** @var \Magento\Wishlist\Model\Wishlist $wishlist */
-        $wishlist = $this->_model->getCustomerWishlist(true);
-        $this->assertInstanceOf(
+        $wishlist = $this->model->getCustomerWishlist(true);
+        self::assertInstanceOf(
             \Magento\Wishlist\Model\Wishlist::class,
             $wishlist,
             'New Wish List is expected to be created if existing Customer does not have one yet.'
         );
-        $this->assertEquals(0, $wishlist->getItemsCount(), 'New Wish List must be empty just after creation.');
+        self::assertEquals(0, $wishlist->getItemsCount(), 'New Wish List must be empty just after creation.');
 
         /** Add new item to wishlist and try to get it using getCustomerWishlist once again */
         $wishlist->addNewItem($productIdFromFixture)->save();
-        $updatedWishlist = $this->_model->getCustomerWishlist(true);
-        $this->assertEquals(
+        $updatedWishlist = $this->model->getCustomerWishlist(true);
+        self::assertEquals(
             1,
             $updatedWishlist->getItemsCount(),
             'Wish List must contain a Product which was added to it earlier.'
@@ -261,14 +275,14 @@ class CreateTest extends \PHPUnit\Framework\TestCase
 
         /** Try to load wishlist from cache in the class after it is deleted from DB */
         $wishlist->delete();
-        $this->assertSame(
+        self::assertSame(
             $updatedWishlist,
-            $this->_model->getCustomerWishlist(false),
+            $this->model->getCustomerWishlist(false),
             'Wish List cached in class variable is expected to be returned.'
         );
-        $this->assertNotSame(
+        self::assertNotSame(
             $updatedWishlist,
-            $this->_model->getCustomerWishlist(true),
+            $this->model->getCustomerWishlist(true),
             'New Wish List is expected to be created when cache is forced to be refreshed.'
         );
     }
@@ -278,12 +292,12 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      */
     public function testSetBillingAddress()
     {
-        $addressData = $this->_getValidAddressData();
+        $addressData = $this->getValidAddressData();
         /** Validate data before creating address object */
-        $this->_model->setIsValidate(true)->setBillingAddress($addressData);
-        $this->assertInstanceOf(
-            \Magento\Quote\Model\Quote\Address::class,
-            $this->_model->getBillingAddress(),
+        $this->model->setIsValidate(true)->setBillingAddress($addressData);
+        self::assertInstanceOf(
+            Quote\Address::class,
+            $this->model->getBillingAddress(),
             'Billing address object was not created.'
         );
 
@@ -291,7 +305,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             $addressData,
             [
                 'address_type' => 'billing',
-                'quote_id' => $this->_model->getQuote()->getId(),
+                'quote_id' => $this->model->getQuote()->getId(),
                 'street' => "Line1\nLine2",
                 'save_in_address_book' => 0,
                 'region' => '',
@@ -299,10 +313,10 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             ]
         );
 
-        $result = $this->_model->getBillingAddress()->getData();
+        $result = $this->model->getBillingAddress()->getData();
         foreach ($expectedAddressData as $key => $value) {
-            $this->assertArrayHasKey($key, $result);
-            $this->assertEquals($value, $result[$key]);
+            self::assertArrayHasKey($key, $result);
+            self::assertEquals($value, $result[$key]);
         }
     }
 
@@ -314,32 +328,32 @@ class CreateTest extends \PHPUnit\Framework\TestCase
     public function testSetBillingAddressValidationErrors()
     {
         $customerIdFromFixture = 1;
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->create(SessionQuote::class);
         $session->setCustomerId($customerIdFromFixture);
-        $invalidAddressData = array_merge($this->_getValidAddressData(), ['firstname' => '', 'lastname' => '']);
+        $invalidAddressData = array_merge($this->getValidAddressData(), ['firstname' => '', 'lastname' => '']);
         /**
          * Note that validation errors are collected during setBillingAddress() call in the internal class variable,
          * but they are not set to message manager at this step.
          * They are set to message manager only during createOrder() call.
          */
-        $this->_model->setIsValidate(true)->setBillingAddress($invalidAddressData);
+        $this->model->setIsValidate(true)->setBillingAddress($invalidAddressData);
         try {
-            $this->_model->createOrder();
+            $this->model->createOrder();
             $this->fail('Validation errors are expected to lead to exception during createOrder() call.');
         } catch (\Magento\Framework\Exception\LocalizedException $e) {
             /** createOrder is expected to throw exception with empty message when validation error occurs */
         }
         $errorMessages = [];
         /** @var $validationError \Magento\Framework\Message\Error */
-        foreach ($this->_messageManager->getMessages()->getItems() as $validationError) {
+        foreach ($this->messageManager->getMessages()->getItems() as $validationError) {
             $errorMessages[] = $validationError->getText();
         }
-        $this->assertTrue(
+        self::assertTrue(
             in_array('Billing Address: "First Name" is a required value.', $errorMessages),
             'Expected validation message is absent.'
         );
-        $this->assertTrue(
+        self::assertTrue(
             in_array('Billing Address: "Last Name" is a required value.', $errorMessages),
             'Expected validation message is absent.'
         );
@@ -361,9 +375,9 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $orderData = [
             'currency' => 'USD',
             'account' => ['group_id' => '1', 'email' => $customerEmail],
-            'billing_address' => array_merge($this->_getValidAddressData(), ['save_in_address_book' => '1']),
+            'billing_address' => array_merge($this->getValidAddressData(), ['save_in_address_book' => '1']),
             'shipping_address' => array_merge(
-                $this->_getValidAddressData(),
+                $this->getValidAddressData(),
                 ['save_in_address_book' => '1', 'firstname' => $firstNameForShippingAddress]
             ),
             'shipping_method' => $shippingMethod,
@@ -372,7 +386,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         ];
         $paymentData = ['method' => $paymentMethod];
 
-        $this->_preparePreconditionsForCreateOrder(
+        $this->preparePreconditionsForCreateOrder(
             $productIdFromFixture,
             $customerEmail,
             $shippingMethod,
@@ -381,12 +395,12 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             $orderData,
             $paymentMethod
         );
-        $order = $this->_model->createOrder();
-        $this->_verifyCreatedOrder($order, $shippingMethod);
-        /** @var \Magento\Customer\Model\Customer $customer */
-        $customer = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Customer::class);
+        $order = $this->model->createOrder();
+        $this->verifyCreatedOrder($order, $shippingMethod);
+        /** @var Customer $customer */
+        $customer = $this->objectManager->create(Customer::class);
         $customer->load($order->getCustomerId());
-        $this->assertEquals(
+        self::assertEquals(
             $firstNameForShippingAddress,
             $customer->getPrimaryShippingAddress()->getFirstname(),
             'Shipping address is saved incorrectly.'
@@ -408,14 +422,14 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $orderData = [
             'currency' => 'USD',
             'account' => ['group_id' => '1', 'email' => $customerEmail],
-            'billing_address' => array_merge($this->_getValidAddressData(), ['save_in_address_book' => '1']),
+            'billing_address' => array_merge($this->getValidAddressData(), ['save_in_address_book' => '1']),
             'shipping_method' => $shippingMethod,
             'comment' => ['customer_note' => ''],
             'send_confirmation' => false,
         ];
         $paymentData = ['method' => $paymentMethod];
 
-        $this->_preparePreconditionsForCreateOrder(
+        $this->preparePreconditionsForCreateOrder(
             $productIdFromFixture,
             $customerEmail,
             $shippingMethod,
@@ -424,12 +438,12 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             $orderData,
             $paymentMethod
         );
-        $order = $this->_model->createOrder();
+        $order = $this->model->createOrder();
         //Check, order considering decimal qty in product.
         foreach ($order->getItems() as $orderItem) {
             self::assertTrue($orderItem->getIsQtyDecimal());
         }
-        $this->_verifyCreatedOrder($order, $shippingMethod);
+        $this->verifyCreatedOrder($order, $shippingMethod);
     }
 
     /**
@@ -454,14 +468,14 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $orderData = [
             'currency' => 'USD',
             'account' => ['group_id' => '1', 'email' => $customerEmail],
-            'billing_address' => array_merge($this->_getValidAddressData(), ['save_in_address_book' => '1']),
+            'billing_address' => array_merge($this->getValidAddressData(), ['save_in_address_book' => '1']),
             'shipping_method' => $shippingMethod,
             'comment' => ['customer_note' => ''],
             'send_confirmation' => false,
         ];
         $paymentData = ['method' => $paymentMethod];
 
-        $this->_preparePreconditionsForCreateOrder(
+        $this->preparePreconditionsForCreateOrder(
             $productIdFromFixture,
             $customerEmail,
             $shippingMethod,
@@ -475,17 +489,17 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $orderManagement = $this->getMockForAbstractClass(OrderManagementInterface::class);
         $orderManagement->method('place')
             ->willThrowException(new \Exception('Can\'t place order'));
-        Bootstrap::getObjectManager()->addSharedInstance($orderManagement, OrderManagementInterface::class);
+        $this->objectManager->addSharedInstance($orderManagement, OrderManagementInterface::class);
         try {
-            $this->_model->createOrder();
+            $this->model->createOrder();
         } catch (\Exception $e) {
-            Bootstrap::getObjectManager()->removeSharedInstance(OrderManagementInterface::class);
+            $this->objectManager->removeSharedInstance(OrderManagementInterface::class);
         }
 
-        $customerEmail = $customerEmailSecondAttempt ? :$this->_model->getQuote()->getCustomer()->getEmail();
+        $customerEmail = $customerEmailSecondAttempt ? :$this->model->getQuote()->getCustomer()->getEmail();
         $orderData['account']['email'] = $customerEmailSecondAttempt;
 
-        $this->_preparePreconditionsForCreateOrder(
+        $this->preparePreconditionsForCreateOrder(
             $productIdFromFixture,
             $customerEmail,
             $shippingMethod,
@@ -495,8 +509,8 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             $paymentMethod
         );
 
-        $order = $this->_model->createOrder();
-        $this->_verifyCreatedOrder($order, $shippingMethod);
+        $order = $this->model->createOrder();
+        $this->verifyCreatedOrder($order, $shippingMethod);
     }
 
     /**
@@ -537,9 +551,9 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $firstNameForShippingAddress = 'FirstNameForShipping';
         $orderData = [
             'currency' => 'USD',
-            'billing_address' => array_merge($this->_getValidAddressData(), ['save_in_address_book' => '1']),
+            'billing_address' => array_merge($this->getValidAddressData(), ['save_in_address_book' => '1']),
             'shipping_address' => array_merge(
-                $this->_getValidAddressData(),
+                $this->getValidAddressData(),
                 ['save_in_address_book' => '1', 'firstname' => $firstNameForShippingAddress]
             ),
             'shipping_method' => $shippingMethod,
@@ -548,7 +562,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         ];
         $paymentData = ['method' => $paymentMethod];
 
-        $this->_preparePreconditionsForCreateOrder(
+        $this->preparePreconditionsForCreateOrder(
             $productIdFromFixture,
             $customerEmailFromFixture,
             $shippingMethod,
@@ -558,12 +572,15 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             $paymentMethod,
             $customerIdFromFixture
         );
-        $order = $this->_model->createOrder();
-        $this->_verifyCreatedOrder($order, $shippingMethod);
-        $this->getCustomerRegistry()->remove($order->getCustomerId());
-        $customer = $this->getCustomerById($order->getCustomerId());
-        $address = $this->getAddressById($customer->getDefaultShipping());
-        $this->assertEquals(
+        $order = $this->model->createOrder();
+        $this->verifyCreatedOrder($order, $shippingMethod);
+        $this->objectManager->get(CustomerRegistry::class)
+            ->remove($order->getCustomerId());
+        $customer = $this->objectManager->get(CustomerRepositoryInterface::class)
+            ->getById($order->getCustomerId());
+        $address = $this->objectManager->get(AddressRepositoryInterface::class)
+            ->getById($customer->getDefaultShipping());
+        self::assertEquals(
             $firstNameForShippingAddress,
             $address->getFirstname(),
             'Shipping address is saved incorrectly.'
@@ -586,14 +603,14 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $shippingAddressAsBilling = 1;
         $orderData = [
             'currency' => 'USD',
-            'billing_address' => array_merge($this->_getValidAddressData(), ['save_in_address_book' => '1']),
+            'billing_address' => array_merge($this->getValidAddressData(), ['save_in_address_book' => '1']),
             'shipping_method' => $shippingMethod,
             'comment' => ['customer_note' => ''],
             'send_confirmation' => false,
         ];
         $paymentData = ['method' => $paymentMethod];
 
-        $this->_preparePreconditionsForCreateOrder(
+        $this->preparePreconditionsForCreateOrder(
             $productIdFromFixture,
             $customerEmailFromFixture,
             $shippingMethod,
@@ -603,8 +620,8 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             $paymentMethod,
             $customerIdFromFixture
         );
-        $order = $this->_model->createOrder();
-        $this->_verifyCreatedOrder($order, $shippingMethod);
+        $order = $this->model->createOrder();
+        $this->verifyCreatedOrder($order, $shippingMethod);
     }
 
     /**
@@ -617,21 +634,21 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $fixtureCustomerId = 1;
 
         /** Preconditions */
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->create(SessionQuote::class);
         $session->setCustomerId($fixtureCustomerId);
-        /** @var $quoteFixture \Magento\Quote\Model\Quote */
-        $quoteFixture = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class);
+        /** @var $quoteFixture Quote */
+        $quoteFixture = $this->objectManager->create(Quote::class);
         $quoteFixture->load('test01', 'reserved_order_id');
         $quoteFixture->setCustomerIsGuest(false)->setCustomerId($fixtureCustomerId)->save();
 
         /** SUT execution */
-        $customerQuote = $this->_model->getCustomerCart();
-        $this->assertEquals($quoteFixture->getId(), $customerQuote->getId(), 'Quote ID is invalid.');
+        $customerQuote = $this->model->getCustomerCart();
+        self::assertEquals($quoteFixture->getId(), $customerQuote->getId(), 'Quote ID is invalid.');
 
         /** Try to load quote once again to ensure that caching works correctly */
-        $customerQuoteFromCache = $this->_model->getCustomerCart();
-        $this->assertSame($customerQuote, $customerQuoteFromCache, 'Customer quote caching does not work correctly.');
+        $customerQuoteFromCache = $this->model->getCustomerCart();
+        self::assertSame($customerQuote, $customerQuoteFromCache, 'Customer quote caching does not work correctly.');
     }
 
     /**
@@ -644,20 +661,20 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $fixtureCustomerId = 1;
 
         /** Preconditions */
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->create(SessionQuote::class);
         $session->setCustomerId($fixtureCustomerId);
-        /** @var $quoteFixture \Magento\Quote\Model\Quote */
-        $quoteFixture = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class);
+        /** @var $quoteFixture Quote */
+        $quoteFixture = $this->objectManager->create(Quote::class);
         $quoteFixture->load('test01', 'reserved_order_id');
         $quoteFixture->setCustomerIsGuest(false)->setCustomerId($fixtureCustomerId)->save();
 
-        $customerQuote = $this->_model->getCustomerCart();
+        $customerQuote = $this->model->getCustomerCart();
         $item = $customerQuote->getAllVisibleItems()[0];
 
-        $this->_model->moveQuoteItem($item, 'cart', 3);
-        $this->assertEquals(4, $item->getQty(), 'Number of Qty isn\'t correct for Quote item.');
-        $this->assertEquals(3, $item->getQtyToAdd(), 'Number of added qty isn\'t correct for Quote item.');
+        $this->model->moveQuoteItem($item, 'cart', 3);
+        self::assertEquals(4, $item->getQty(), 'Number of Qty isn\'t correct for Quote item.');
+        self::assertEquals(3, $item->getQtyToAdd(), 'Number of added qty isn\'t correct for Quote item.');
     }
 
     /**
@@ -671,14 +688,14 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         $customerEmailFromFixture = 'customer@example.com';
 
         /** Preconditions */
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->create(SessionQuote::class);
         $session->setCustomerId($customerIdFromFixture);
 
         /** SUT execution */
-        $customerQuote = $this->_model->getCustomerCart();
-        $this->assertNotEmpty($customerQuote->getId(), 'Quote ID is invalid.');
-        $this->assertEquals(
+        $customerQuote = $this->model->getCustomerCart();
+        self::assertNotEmpty($customerQuote->getId(), 'Quote ID is invalid.');
+        self::assertEquals(
             $customerEmailFromFixture,
             $customerQuote->getCustomerEmail(),
             'Customer data is preserved incorrectly in a newly quote.'
@@ -697,7 +714,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      * @param string $paymentMethod
      * @param int|null $customerIdFromFixture
      */
-    protected function _preparePreconditionsForCreateOrder(
+    private function preparePreconditionsForCreateOrder(
         $productIdFromFixture,
         $customerEmail,
         $shippingMethod,
@@ -709,18 +726,18 @@ class CreateTest extends \PHPUnit\Framework\TestCase
     ) {
         /** Disable product options */
         /** @var \Magento\Catalog\Model\Product $product */
-        $product = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
         $product->load($productIdFromFixture)->setHasOptions(false)->save();
 
         /** Set current customer */
-        /** @var \Magento\Backend\Model\Session\Quote $session */
-        $session = Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session\Quote::class);
+        /** @var SessionQuote $session */
+        $session = $this->objectManager->get(SessionQuote::class);
         if ($customerIdFromFixture !== null) {
             $session->setCustomerId($customerIdFromFixture);
 
             /** Unset fake IDs for default billing and shipping customer addresses */
-            /** @var \Magento\Customer\Model\Customer $customer */
-            $customer = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Customer::class);
+            /** @var Customer $customer */
+            $customer = $this->objectManager->create(Customer::class);
             $customer->load($customerIdFromFixture)->setDefaultBilling(null)->setDefaultShipping(null)->save();
         } else {
             /**
@@ -731,48 +748,48 @@ class CreateTest extends \PHPUnit\Framework\TestCase
         }
 
         /** Emulate availability of shipping method (all are disabled by default) */
-        /** @var $rate \Magento\Quote\Model\Quote\Address\Rate */
-        $rate = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote\Address\Rate::class);
+        /** @var $rate Quote\Address\Rate */
+        $rate = $this->objectManager->create(Quote\Address\Rate::class);
         $rate->setCode($shippingMethod);
-        $this->_model->getQuote()->getShippingAddress()->addShippingRate($rate);
+        $this->model->getQuote()->getShippingAddress()->addShippingRate($rate);
 
-        $this->_model->setShippingAsBilling($shippingAddressAsBilling);
-        $this->_model->addProduct($productIdFromFixture, ['qty' => 1]);
-        $this->_model->setPaymentData($paymentData);
-        $this->_model->setIsValidate(true)->importPostData($orderData);
+        $this->model->setShippingAsBilling($shippingAddressAsBilling);
+        $this->model->addProduct($productIdFromFixture, ['qty' => 1]);
+        $this->model->setPaymentData($paymentData);
+        $this->model->setIsValidate(true)->importPostData($orderData);
 
         /** Check preconditions */
 
-        $this->assertEquals(
+        self::assertEquals(
             0,
-            $this->_messageManager->getMessages()->getCount(),
+            $this->messageManager->getMessages()->getCount(),
             "Precondition failed: Errors occurred before SUT execution."
         );
         /** Selectively check quote data */
-        $createOrderData = $this->_model->getData();
-        $this->assertEquals(
+        $createOrderData = $this->model->getData();
+        self::assertEquals(
             $shippingMethod,
             $createOrderData['shipping_method'],
             'Precondition failed: Shipping method specified in create order model is invalid'
         );
-        $this->assertEquals(
+        self::assertEquals(
             'FirstName',
             $createOrderData['billing_address']['firstname'],
             'Precondition failed: Address data is invalid in create order model'
         );
-        $this->assertEquals(
+        self::assertEquals(
             'Simple Product',
-            $this->_model->getQuote()->getItemByProduct($product)->getData('name'),
+            $this->model->getQuote()->getItemByProduct($product)->getData('name'),
             'Precondition failed: Quote items data is invalid in create order model'
         );
-        $this->assertEquals(
+        self::assertEquals(
             $customerEmail,
-            $this->_model->getQuote()->getCustomer()->getEmail(),
+            $this->model->getQuote()->getCustomer()->getEmail(),
             'Precondition failed: Customer data is invalid in create order model'
         );
-        $this->assertEquals(
+        self::assertEquals(
             $paymentMethod,
-            $this->_model->getQuote()->getPayment()->getData('method'),
+            $this->model->getQuote()->getPayment()->getData('method'),
             'Precondition failed: Payment method data is invalid in create order model'
         );
     }
@@ -780,26 +797,26 @@ class CreateTest extends \PHPUnit\Framework\TestCase
     /**
      * Ensure that order is created correctly via createOrder().
      *
-     * @param \Magento\Sales\Model\Order $order
+     * @param Order $order
      * @param string $shippingMethod
      */
-    protected function _verifyCreatedOrder($order, $shippingMethod)
+    private function verifyCreatedOrder($order, $shippingMethod)
     {
         /** Selectively check order data */
         $orderData = $order->getData();
-        $this->assertNotEmpty($orderData['increment_id'], 'Order increment ID is empty.');
-        $this->assertEquals($this->_model->getQuote()->getId(), $orderData['quote_id'], 'Quote ID is invalid.');
-        $this->assertEquals(
-            $this->_model->getQuote()->getCustomer()->getEmail(),
+        self::assertNotEmpty($orderData['increment_id'], 'Order increment ID is empty.');
+        self::assertEquals($this->model->getQuote()->getId(), $orderData['quote_id'], 'Quote ID is invalid.');
+        self::assertEquals(
+            $this->model->getQuote()->getCustomer()->getEmail(),
             $orderData['customer_email'],
             'Customer email is invalid.'
         );
-        $this->assertEquals(
-            $this->_model->getQuote()->getCustomer()->getFirstname(),
+        self::assertEquals(
+            $this->model->getQuote()->getCustomer()->getFirstname(),
             $orderData['customer_firstname'],
             'Customer first name is invalid.'
         );
-        $this->assertEquals($shippingMethod, $orderData['shipping_method'], 'Shipping method is invalid.');
+        self::assertEquals($shippingMethod, $orderData['shipping_method'], 'Shipping method is invalid.');
     }
 
     /**
@@ -807,7 +824,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase
      *
      * @return array
      */
-    protected function _getValidAddressData()
+    private function getValidAddressData()
     {
         return [
             'prefix' => 'prefix',
@@ -829,48 +846,4 @@ class CreateTest extends \PHPUnit\Framework\TestCase
             'vat_id' => ''
         ];
     }
-
-    /**
-     * @param int $id
-     * @return \Magento\Customer\Api\Data\CustomerInterface
-     */
-    private function getCustomerById($id)
-    {
-        return $this->getCustomerRepository()->getById($id);
-    }
-
-    /**
-     * @return \Magento\Customer\Api\CustomerRepositoryInterface
-     */
-    private function getCustomerRepository()
-    {
-        return Bootstrap::getObjectManager()->create(\Magento\Customer\Api\CustomerRepositoryInterface::class);
-    }
-
-    /**
-     * @param int $id
-     * @return \Magento\Customer\Api\Data\AddressInterface
-     */
-    private function getAddressById($id)
-    {
-        return $this->getAddressRepository()->getById($id);
-    }
-
-    /**
-     * @return \Magento\Customer\Api\AddressRepositoryInterface
-     */
-    private function getAddressRepository()
-    {
-        /** @var \Magento\Customer\Api\AddressRepositoryInterface $addressRepository */
-        return Bootstrap::getObjectManager()->create(\Magento\Customer\Api\AddressRepositoryInterface::class);
-    }
-
-    /**
-     * @return \Magento\Customer\Model\CustomerRegistry
-     */
-    private function getCustomerRegistry()
-    {
-        /** @var \Magento\Customer\Model\CustomerRegistry $addressRepository */
-        return Bootstrap::getObjectManager()->get(\Magento\Customer\Model\CustomerRegistry::class);
-    }
 }
diff --git a/lib/internal/Magento/Framework/Data/Form/Filter/Date.php b/lib/internal/Magento/Framework/Data/Form/Filter/Date.php
index 8765e136e2897a6da3dacb3fafefbb492180681c..864c0f3e27e6912c52f558f59bbbbce02a6b6f70 100644
--- a/lib/internal/Magento/Framework/Data/Form/Filter/Date.php
+++ b/lib/internal/Magento/Framework/Data/Form/Filter/Date.php
@@ -54,6 +54,10 @@ class Date implements \Magento\Framework\Data\Form\Filter\FilterInterface
      */
     public function inputFilter($value)
     {
+        if (!$value) {
+            return $value;
+        }
+
         $filterInput = new \Zend_Filter_LocalizedToNormalized(
             ['date_format' => $this->_dateFormat, 'locale' => $this->localeResolver->getLocale()]
         );
@@ -74,6 +78,10 @@ class Date implements \Magento\Framework\Data\Form\Filter\FilterInterface
      */
     public function outputFilter($value)
     {
+        if (!$value) {
+            return $value;
+        }
+
         $filterInput = new \Zend_Filter_LocalizedToNormalized(
             ['date_format' => DateTime::DATE_INTERNAL_FORMAT, 'locale' => $this->localeResolver->getLocale()]
         );