diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml index b951fd2c19495..c829a2f01fa9c 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml @@ -43,7 +43,7 @@ data-validate="{required:true}" value="" placeholder="" - autocomplete="off" + autocomplete="new-password" /> diff --git a/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml b/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml index 03d52ab9e5703..2eebcdbe65749 100644 --- a/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml +++ b/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml @@ -73,7 +73,7 @@
-
+
@@ -119,7 +119,7 @@
- +
diff --git a/app/code/Magento/Braintree/Block/Paypal/Button.php b/app/code/Magento/Braintree/Block/Paypal/Button.php index 8a90fc23ad123..efd9e473699c3 100644 --- a/app/code/Magento/Braintree/Block/Paypal/Button.php +++ b/app/code/Magento/Braintree/Block/Paypal/Button.php @@ -5,13 +5,13 @@ */ namespace Magento\Braintree\Block\Paypal; -use Magento\Checkout\Model\Session; +use Magento\Braintree\Gateway\Config\PayPal\Config; +use Magento\Braintree\Model\Ui\ConfigProvider; use Magento\Catalog\Block\ShortcutInterface; -use Magento\Framework\View\Element\Template; +use Magento\Checkout\Model\Session; use Magento\Framework\Locale\ResolverInterface; -use Magento\Braintree\Model\Ui\ConfigProvider; +use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\Template\Context; -use Magento\Braintree\Gateway\Config\PayPal\Config; use Magento\Payment\Model\MethodInterface; /** @@ -110,7 +110,7 @@ public function getContainerId() */ public function getLocale() { - return strtolower($this->localeResolver->getLocale()); + return $this->localeResolver->getLocale(); } /** diff --git a/app/code/Magento/Braintree/Model/LocaleResolver.php b/app/code/Magento/Braintree/Model/LocaleResolver.php new file mode 100644 index 0000000000000..cebd90dffc70e --- /dev/null +++ b/app/code/Magento/Braintree/Model/LocaleResolver.php @@ -0,0 +1,93 @@ +resolver = $resolver; + $this->config = $config; + } + + /** + * @inheritdoc + */ + public function getDefaultLocalePath() + { + return $this->resolver->getDefaultLocalePath(); + } + + /** + * @inheritdoc + */ + public function setDefaultLocale($locale) + { + return $this->resolver->setDefaultLocale($locale); + } + + /** + * @inheritdoc + */ + public function getDefaultLocale() + { + return $this->resolver->getDefaultLocale(); + } + + /** + * @inheritdoc + */ + public function setLocale($locale = null) + { + return $this->resolver->setLocale($locale); + } + + /** + * Gets store's locale or the `en_US` locale if store's locale does not supported by PayPal. + * + * @return string + */ + public function getLocale() + { + $locale = $this->resolver->getLocale(); + $allowedLocales = $this->config->getValue('supported_locales'); + + return strpos($allowedLocales, $locale) !== false ? $locale : 'en_US'; + } + + /** + * @inheritdoc + */ + public function emulate($scopeId) + { + return $this->resolver->emulate($scopeId); + } + + /** + * @inheritdoc + */ + public function revert() + { + return $this->resolver->revert(); + } +} diff --git a/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php b/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php index fc400cb375ea7..e06b913db8ef4 100644 --- a/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php +++ b/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php @@ -54,7 +54,7 @@ public function getConfig() 'title' => $this->config->getTitle(), 'isAllowShippingAddressOverride' => $this->config->isAllowToEditShippingAddress(), 'merchantName' => $this->config->getMerchantName(), - 'locale' => strtolower($this->resolver->getLocale()), + 'locale' => $this->resolver->getLocale(), 'paymentAcceptanceMarkSrc' => 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-medium.png', 'vaultCode' => self::PAYPAL_VAULT_CODE, diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php index 92d5f0a41716b..ea46d8ee77a8a 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php @@ -49,42 +49,35 @@ protected function setUp() /** * Run test getConfig method * - * @param array $config + * @param array $expected * @dataProvider getConfigDataProvider */ public function testGetConfig($expected) { - $this->config->expects(static::once()) - ->method('isActive') + $this->config->method('isActive') ->willReturn(true); - $this->config->expects(static::once()) - ->method('isAllowToEditShippingAddress') + $this->config->method('isAllowToEditShippingAddress') ->willReturn(true); - $this->config->expects(static::once()) - ->method('getMerchantName') + $this->config->method('getMerchantName') ->willReturn('Test'); - $this->config->expects(static::once()) - ->method('getTitle') + $this->config->method('getTitle') ->willReturn('Payment Title'); - $this->localeResolver->expects(static::once()) - ->method('getLocale') + $this->localeResolver->method('getLocale') ->willReturn('en_US'); - $this->config->expects(static::once()) - ->method('isSkipOrderReview') + $this->config->method('isSkipOrderReview') ->willReturn(false); - $this->config->expects(static::once()) - ->method('getPayPalIcon') + $this->config->method('getPayPalIcon') ->willReturn([ 'width' => 30, 'height' => 26, 'url' => 'https://icon.test.url' ]); - static::assertEquals($expected, $this->configProvider->getConfig()); + self::assertEquals($expected, $this->configProvider->getConfig()); } /** @@ -101,7 +94,7 @@ public function getConfigDataProvider() 'title' => 'Payment Title', 'isAllowShippingAddressOverride' => true, 'merchantName' => 'Test', - 'locale' => 'en_us', + 'locale' => 'en_US', 'paymentAcceptanceMarkSrc' => 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-medium.png', 'vaultCode' => ConfigProvider::PAYPAL_VAULT_CODE, diff --git a/app/code/Magento/Braintree/etc/config.xml b/app/code/Magento/Braintree/etc/config.xml index f1bbdf79b7d7e..e91f59fb0740e 100644 --- a/app/code/Magento/Braintree/etc/config.xml +++ b/app/code/Magento/Braintree/etc/config.xml @@ -34,7 +34,7 @@ processing sandbox 0 - + cvv,number @@ -66,6 +66,7 @@ 1 processorResponseCode,processorResponseText,paymentId processorResponseCode,processorResponseText,paymentId,payerEmail + en_US,en_GB,en_AU,da_DK,fr_FR,fr_CA,de_DE,zh_HK,it_IT,nl_NL,no_NO,pl_PL,es_ES,sv_SE,tr_TR,pt_BR,ja_JP,id_ID,ko_KR,pt_PT,ru_RU,th_TH,zh_CN,zh_TW BraintreeCreditCardVaultFacade diff --git a/app/code/Magento/Braintree/etc/frontend/di.xml b/app/code/Magento/Braintree/etc/frontend/di.xml index 1983bb1f20e62..ea417c407dffd 100644 --- a/app/code/Magento/Braintree/etc/frontend/di.xml +++ b/app/code/Magento/Braintree/etc/frontend/di.xml @@ -46,6 +46,7 @@ + Magento\Braintree\Model\LocaleResolver Magento_Braintree::paypal/button.phtml braintree.paypal.mini-cart @@ -54,4 +55,10 @@ BraintreePayPalFacade + + + + Magento\Braintree\Model\LocaleResolver + + diff --git a/app/code/Magento/Braintree/view/frontend/requirejs-config.js b/app/code/Magento/Braintree/view/frontend/requirejs-config.js index 8b347d799007a..9fc38064677ef 100644 --- a/app/code/Magento/Braintree/view/frontend/requirejs-config.js +++ b/app/code/Magento/Braintree/view/frontend/requirejs-config.js @@ -6,7 +6,7 @@ var config = { map: { '*': { - braintree: 'https://js.braintreegateway.com/js/braintree-2.25.0.min.js' + braintree: 'https://js.braintreegateway.com/js/braintree-2.32.0.min.js' } } }; diff --git a/app/code/Magento/Braintree/view/frontend/web/js/paypal/button.js b/app/code/Magento/Braintree/view/frontend/web/js/paypal/button.js index eaac1cd116082..3ac50fbcb47cc 100644 --- a/app/code/Magento/Braintree/view/frontend/web/js/paypal/button.js +++ b/app/code/Magento/Braintree/view/frontend/web/js/paypal/button.js @@ -105,7 +105,11 @@ define( event.preventDefault(); registry.get(self.integrationName, function (integration) { - integration.paypal.initAuthFlow(); + try { + integration.paypal.initAuthFlow(); + } catch (e) { + $this.attr('disabled', 'disabled'); + } }); }); }.bind(this); diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js index 182ec5e7168e8..9804ee8489625 100644 --- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -13,7 +13,8 @@ define([ 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Vault/js/view/payment/vault-enabler', - 'Magento_Checkout/js/action/create-billing-address' + 'Magento_Checkout/js/action/create-billing-address', + 'mage/translate' ], function ( $, _, @@ -23,7 +24,8 @@ define([ fullScreenLoader, additionalValidators, VaultEnabler, - createBillingAddress + createBillingAddress, + $t ) { 'use strict'; @@ -403,7 +405,13 @@ define([ */ payWithPayPal: function () { if (additionalValidators.validate()) { - Braintree.checkout.paypal.initAuthFlow(); + try { + Braintree.checkout.paypal.initAuthFlow(); + } catch (e) { + this.messageContainer.addErrorMessage({ + message: $t('Payment ' + this.getTitle() + ' can\'t be initialized.') + }); + } } }, diff --git a/app/code/Magento/Catalog/etc/mview.xml b/app/code/Magento/Catalog/etc/mview.xml index 4213faf9307b5..7ae38a7f2d0e1 100644 --- a/app/code/Magento/Catalog/etc/mview.xml +++ b/app/code/Magento/Catalog/etc/mview.xml @@ -36,7 +36,6 @@
-
diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml index 508ad26bf9378..96055b73d363b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml @@ -27,7 +27,7 @@ - jpg jpeg gif png svg + jpg jpeg gif png 2097152 theme/design_config_fileUploader/save @@ -87,7 +87,7 @@ - jpg jpeg gif png svg + jpg jpeg gif png 2097152 theme/design_config_fileUploader/save @@ -147,7 +147,7 @@ - jpg jpeg gif png svg + jpg jpeg gif png 2097152 theme/design_config_fileUploader/save diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index b83b1b78e25ba..dc49b86a6a69c 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1228,15 +1228,15 @@ protected function _saveLinks() 'linked_product_id' => $linkedId, 'link_type_id' => $linkId, ]; - if (!empty($linkPositions[$linkedKey])) { - $positionRows[] = [ - 'link_id' => $productLinkKeys[$linkKey], - 'product_link_attribute_id' => $positionAttrId[$linkId], - 'value' => $linkPositions[$linkedKey], - ]; - } - $nextLinkId++; } + if (!empty($linkPositions[$linkedKey])) { + $positionRows[] = [ + 'link_id' => $productLinkKeys[$linkKey], + 'product_link_attribute_id' => $positionAttrId[$linkId], + 'value' => $linkPositions[$linkedKey], + ]; + } + $nextLinkId++; } } } diff --git a/app/code/Magento/CatalogRule/etc/mview.xml b/app/code/Magento/CatalogRule/etc/mview.xml index 0fc3be87057be..2990c03ae0159 100644 --- a/app/code/Magento/CatalogRule/etc/mview.xml +++ b/app/code/Magento/CatalogRule/etc/mview.xml @@ -18,7 +18,6 @@
-
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php index d600cc892be7d..77ea3e1c312e1 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php @@ -41,7 +41,7 @@ public function __construct( } /** - * Generate list based on categories + * Generate product rewrites for anchor categories * * @param int $storeId * @param Product $product diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/CanonicalUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/CanonicalUrlRewriteGenerator.php index 69705c072e494..41e1a880d7ad7 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Product/CanonicalUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/CanonicalUrlRewriteGenerator.php @@ -30,7 +30,7 @@ public function __construct(ProductUrlPathGenerator $productUrlPathGenerator, Ur } /** - * Generate list based on store view + * Generate product rewrites without categories * * @param int $storeId * @param Product $product diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/CategoriesUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/CategoriesUrlRewriteGenerator.php index 1d60565f28b98..ddad00b42a1da 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Product/CategoriesUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/CategoriesUrlRewriteGenerator.php @@ -31,7 +31,7 @@ public function __construct(ProductUrlPathGenerator $productUrlPathGenerator, Ur } /** - * Generate list based on categories + * Generate product rewrites with categories * * @param int $storeId * @param Product $product diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/CurrentUrlRewritesRegenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/CurrentUrlRewritesRegenerator.php index 70e4ec3d92875..d163ef8f067f3 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Product/CurrentUrlRewritesRegenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/CurrentUrlRewritesRegenerator.php @@ -6,6 +6,7 @@ namespace Magento\CatalogUrlRewrite\Model\Product; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\CategoryRepository; use Magento\Catalog\Model\Product; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; use Magento\UrlRewrite\Model\OptionProvider; @@ -56,19 +57,24 @@ class CurrentUrlRewritesRegenerator /** @var \Magento\UrlRewrite\Model\MergeDataProvider */ private $mergeDataProviderPrototype; + /** @var CategoryRepository */ + private $categoryRepository; + /** * @param UrlFinderInterface $urlFinder * @param ProductUrlPathGenerator $productUrlPathGenerator * @param UrlRewriteFactory $urlRewriteFactory * @param UrlRewriteFinder|null $urlRewriteFinder * @param \Magento\UrlRewrite\Model\MergeDataProviderFactory|null $mergeDataProviderFactory + * @param CategoryRepository|null $categoryRepository */ public function __construct( UrlFinderInterface $urlFinder, ProductUrlPathGenerator $productUrlPathGenerator, UrlRewriteFactory $urlRewriteFactory, UrlRewriteFinder $urlRewriteFinder = null, - MergeDataProviderFactory $mergeDataProviderFactory = null + MergeDataProviderFactory $mergeDataProviderFactory = null, + CategoryRepository $categoryRepository = null ) { $this->urlFinder = $urlFinder; $this->productUrlPathGenerator = $productUrlPathGenerator; @@ -78,11 +84,12 @@ public function __construct( if (!isset($mergeDataProviderFactory)) { $mergeDataProviderFactory = ObjectManager::getInstance()->get(MergeDataProviderFactory::class); } + $this->categoryRepository = $categoryRepository ?: ObjectManager::getInstance()->get(CategoryRepository::class); $this->mergeDataProviderPrototype = $mergeDataProviderFactory->create(); } /** - * Generate list based on current rewrites + * Generate product rewrites based on current rewrites without anchor categories * * @param int $storeId * @param Product $product @@ -115,6 +122,52 @@ public function generate($storeId, Product $product, ObjectRegistry $productCate return $mergeDataProvider->getData(); } + /** + * Generate product rewrites for anchor categories based on current rewrites + * + * @param int $storeId + * @param Product $product + * @param ObjectRegistry $productCategories + * @param int|null $rootCategoryId + * @return UrlRewrite[] + */ + public function generateAnchor( + $storeId, + Product $product, + ObjectRegistry $productCategories, + $rootCategoryId = null + ) { + $anchorCategoryIds = []; + $mergeDataProvider = clone $this->mergeDataProviderPrototype; + + $currentUrlRewrites = $this->urlRewriteFinder->findAllByData( + $product->getEntityId(), + $storeId, + ProductUrlRewriteGenerator::ENTITY_TYPE, + $rootCategoryId + ); + + foreach ($productCategories->getList() as $productCategory) { + $anchorCategoryIds = array_merge($productCategory->getAnchorsAbove(), $anchorCategoryIds); + } + + foreach ($currentUrlRewrites as $currentUrlRewrite) { + $metadata = $currentUrlRewrite->getMetadata(); + if (isset($metadata['category_id']) && $metadata['category_id'] > 0) { + $category = $this->categoryRepository->get($metadata['category_id'], $storeId); + if (in_array($category->getId(), $anchorCategoryIds)) { + $mergeDataProvider->merge( + $currentUrlRewrite->getIsAutogenerated() + ? $this->generateForAutogenerated($currentUrlRewrite, $storeId, $category, $product) + : $this->generateForCustom($currentUrlRewrite, $storeId, $category, $product) + ); + } + } + } + + return $mergeDataProvider->getData(); + } + /** * @param UrlRewrite $url * @param int $storeId diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php index eb9a1881f5baa..2795bb02e9612 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php @@ -171,7 +171,14 @@ public function generateForSpecificStoreView($storeId, $productCategories, Produ $mergeDataProvider->merge( $this->anchorUrlRewriteGenerator->generate($storeId, $product, $productCategories) ); - + $mergeDataProvider->merge( + $this->currentUrlRewritesRegenerator->generateAnchor( + $storeId, + $product, + $productCategories, + $rootCategoryId + ) + ); return $mergeDataProvider->getData(); } diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php index e1a670e9d3597..c8816b8e4daf7 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php @@ -80,11 +80,11 @@ public function __construct( public function generateProductUrlRewrites(\Magento\Catalog\Model\Category $category) { $mergeDataProvider = clone $this->mergeDataProviderPrototype; - $this->isSkippedProduct = []; + $this->isSkippedProduct[$category->getEntityId()] = []; $saveRewriteHistory = $category->getData('save_rewrites_history'); $storeId = $category->getStoreId(); if ($category->getAffectedProductIds()) { - $this->isSkippedProduct = $category->getAffectedProductIds(); + $this->isSkippedProduct[$category->getEntityId()] = $category->getAffectedProductIds(); $collection = $this->productCollectionFactory->create() ->setStoreId($storeId) ->addIdFilter($category->getAffectedProductIds()) @@ -137,17 +137,25 @@ public function getCategoryProductsUrlRewrites( $rootCategoryId = null ) { $mergeDataProvider = clone $this->mergeDataProviderPrototype; + /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */ - $productCollection = $category->getProductCollection() + $productCollection = $this->productCollectionFactory->create(); + + $productCollection->addCategoriesFilter(['eq' => [$category->getEntityId()]]) + ->setStoreId($storeId) ->addAttributeToSelect('name') ->addAttributeToSelect('visibility') ->addAttributeToSelect('url_key') ->addAttributeToSelect('url_path'); + foreach ($productCollection as $product) { - if (in_array($product->getId(), $this->isSkippedProduct)) { + if ( + isset($this->isSkippedProduct[$category->getEntityId()]) && + in_array($product->getId(), $this->isSkippedProduct[$category->getEntityId()]) + ) { continue; } - $this->isSkippedProduct[] = $product->getId(); + $this->isSkippedProduct[$category->getEntityId()][] = $product->getId(); $product->setStoreId($storeId); $product->setData('save_rewrites_history', $saveRewriteHistory); $mergeDataProvider->merge( diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php index 16f6c5a1d9d03..d2334c862b17c 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php @@ -137,6 +137,8 @@ public function testGenerationForGlobalScope() ->setStoreId(3); $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate') ->will($this->returnValue([$current])); + $this->currentUrlRewritesRegenerator->expects($this->any())->method('generateAnchor') + ->will($this->returnValue([$current])); $anchorCategories = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite([], $this->serializer); $anchorCategories->setRequestPath('category-4') ->setStoreId(4); @@ -178,6 +180,8 @@ public function testGenerationForSpecificStore() ->will($this->returnValue([])); $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate') ->will($this->returnValue([])); + $this->currentUrlRewritesRegenerator->expects($this->any())->method('generateAnchor') + ->will($this->returnValue([])); $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate') ->will($this->returnValue([])); diff --git a/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php b/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php index 63eed9762d580..63bb40867fcb3 100644 --- a/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php +++ b/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php @@ -321,7 +321,7 @@ protected function getDefaultValue($attributeCode) if (!$this->getCustomer()) { return null; } - if (in_array($attributeCode, ['prefix', 'firstname', 'lastname', 'suffix'])) { + if (in_array($attributeCode, ['prefix', 'firstname', 'middlename', 'lastname', 'suffix'])) { $methodName = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $attributeCode))); return $this->getCustomer()->{$methodName}(); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/checkout-data.js b/app/code/Magento/Checkout/view/frontend/web/js/checkout-data.js index 6784ca111674c..9c0ef8bb58c07 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/checkout-data.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/checkout-data.js @@ -31,14 +31,14 @@ define([ if ($.isEmptyObject(data)) { data = { - 'selectedShippingAddress': null, - 'shippingAddressFromData': null, - 'newCustomerShippingAddress': null, - 'selectedShippingRate': null, - 'selectedPaymentMethod': null, - 'selectedBillingAddress': null, - 'billingAddressFormData': null, - 'newCustomerBillingAddress': null + 'selectedShippingAddress': null, //Selected shipping address pulled from persistence storage + 'shippingAddressFromData': null, //Shipping address pulled from persistence storage + 'newCustomerShippingAddress': null, //Shipping address pulled from persistence storage for customer + 'selectedShippingRate': null, //Shipping rate pulled from persistence storage + 'selectedPaymentMethod': null, //Payment method pulled from persistence storage + 'selectedBillingAddress': null, //Selected billing address pulled from persistence storage + 'billingAddressFromData': null, //Billing address pulled from persistence storage + 'newCustomerBillingAddress': null //Billing address pulled from persistence storage for new customer }; saveData(data); } @@ -48,6 +48,8 @@ define([ return { /** + * Setting the selected shipping address pulled from persistence storage + * * @param {Object} data */ setSelectedShippingAddress: function (data) { @@ -58,6 +60,8 @@ define([ }, /** + * Pulling the selected shipping address from persistence storage + * * @return {*} */ getSelectedShippingAddress: function () { @@ -65,6 +69,8 @@ define([ }, /** + * Setting the shipping address pulled from persistence storage + * * @param {Object} data */ setShippingAddressFromData: function (data) { @@ -75,6 +81,8 @@ define([ }, /** + * Pulling the shipping address from persistence storage + * * @return {*} */ getShippingAddressFromData: function () { @@ -82,6 +90,8 @@ define([ }, /** + * Setting the shipping address pulled from persistence storage for new customer + * * @param {Object} data */ setNewCustomerShippingAddress: function (data) { @@ -92,6 +102,8 @@ define([ }, /** + * Pulling the shipping address from persistence storage for new customer + * * @return {*} */ getNewCustomerShippingAddress: function () { @@ -99,6 +111,8 @@ define([ }, /** + * Setting the selected shipping rate pulled from persistence storage + * * @param {Object} data */ setSelectedShippingRate: function (data) { @@ -109,6 +123,8 @@ define([ }, /** + * Pulling the selected shipping rate from local storage + * * @return {*} */ getSelectedShippingRate: function () { @@ -116,6 +132,8 @@ define([ }, /** + * Setting the selected payment method pulled from persistence storage + * * @param {Object} data */ setSelectedPaymentMethod: function (data) { @@ -126,6 +144,8 @@ define([ }, /** + * Pulling the payment method from persistence storage + * * @return {*} */ getSelectedPaymentMethod: function () { @@ -133,6 +153,8 @@ define([ }, /** + * Setting the selected billing address pulled from persistence storage + * * @param {Object} data */ setSelectedBillingAddress: function (data) { @@ -143,6 +165,8 @@ define([ }, /** + * Pulling the selected billing address from persistence storage + * * @return {*} */ getSelectedBillingAddress: function () { @@ -150,6 +174,8 @@ define([ }, /** + * Setting the billing address pulled from persistence storage + * * @param {Object} data */ setBillingAddressFromData: function (data) { @@ -160,6 +186,8 @@ define([ }, /** + * Pulling the billing address from persistence storage + * * @return {*} */ getBillingAddressFromData: function () { @@ -167,6 +195,8 @@ define([ }, /** + * Setting the billing address pulled from persistence storage for new customer + * * @param {Object} data */ setNewCustomerBillingAddress: function (data) { @@ -177,6 +207,8 @@ define([ }, /** + * Pulling the billing address from persistence storage for new customer + * * @return {*} */ getNewCustomerBillingAddress: function () { @@ -184,6 +216,8 @@ define([ }, /** + * Pulling the email address from persistence storage + * * @return {*} */ getValidatedEmailValue: function () { @@ -193,6 +227,8 @@ define([ }, /** + * Setting the email address pulled from persistence storage + * * @param {String} email */ setValidatedEmailValue: function (email) { @@ -203,6 +239,8 @@ define([ }, /** + * Pulling the email input field value from persistence storage + * * @return {*} */ getInputFieldEmailValue: function () { @@ -212,6 +250,8 @@ define([ }, /** + * Setting the email input field value pulled from persistence storage + * * @param {String} email */ setInputFieldEmailValue: function (email) { diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html index 17754b81849f5..f2baf5d50030e 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html @@ -5,7 +5,7 @@ */ -->
- +

,
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html index 4c3ce84baac4d..f9400227fae09 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html @@ -5,7 +5,7 @@ */ -->
- +

,
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html index c3afce6c4537f..ec41cae0bdc5e 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html @@ -5,7 +5,7 @@ */ --> - +

,
diff --git a/app/code/Magento/Cms/Model/BlockRepository.php b/app/code/Magento/Cms/Model/BlockRepository.php index a06c5fac1bc4e..5f8ec399e9bd6 100644 --- a/app/code/Magento/Cms/Model/BlockRepository.php +++ b/app/code/Magento/Cms/Model/BlockRepository.php @@ -154,25 +154,10 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $criteria $this->collectionProcessor->process($criteria, $collection); - $blocks = []; - /** @var Block $blockModel */ - foreach ($collection as $blockModel) { - $blockData = $this->dataBlockFactory->create(); - $this->dataObjectHelper->populateWithArray( - $blockData, - $blockModel->getData(), - \Magento\Cms\Api\Data\BlockInterface::class - ); - $blocks[] = $this->dataObjectProcessor->buildOutputDataArray( - $blockData, - \Magento\Cms\Api\Data\BlockInterface::class - ); - } - /** @var Data\BlockSearchResultsInterface $searchResults */ $searchResults = $this->searchResultsFactory->create(); $searchResults->setSearchCriteria($criteria); - $searchResults->setItems($blocks); + $searchResults->setItems($collection->getItems()); $searchResults->setTotalCount($collection->getSize()); return $searchResults; } diff --git a/app/code/Magento/Cms/Model/PageRepository.php b/app/code/Magento/Cms/Model/PageRepository.php index 033289bf8fb8e..521a975c885dd 100644 --- a/app/code/Magento/Cms/Model/PageRepository.php +++ b/app/code/Magento/Cms/Model/PageRepository.php @@ -157,25 +157,10 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $criteria $this->collectionProcessor->process($criteria, $collection); - $pages = []; - /** @var Page $pageModel */ - foreach ($collection as $pageModel) { - $pageData = $this->dataPageFactory->create(); - $this->dataObjectHelper->populateWithArray( - $pageData, - $pageModel->getData(), - \Magento\Cms\Api\Data\PageInterface::class - ); - $pages[] = $this->dataObjectProcessor->buildOutputDataArray( - $pageData, - \Magento\Cms\Api\Data\PageInterface::class - ); - } - /** @var Data\PageSearchResultsInterface $searchResults */ $searchResults = $this->searchResultsFactory->create(); $searchResults->setSearchCriteria($criteria); - $searchResults->setItems($pages); + $searchResults->setItems($collection->getItems()); $searchResults->setTotalCount($collection->getSize()); return $searchResults; } diff --git a/app/code/Magento/Cms/Test/Unit/Model/BlockRepositoryTest.php b/app/code/Magento/Cms/Test/Unit/Model/BlockRepositoryTest.php index dd43f4a0b2287..6e4440ef97b25 100644 --- a/app/code/Magento/Cms/Test/Unit/Model/BlockRepositoryTest.php +++ b/app/code/Magento/Cms/Test/Unit/Model/BlockRepositoryTest.php @@ -263,22 +263,8 @@ public function testGetList() ->willReturnSelf(); $this->blockSearchResult->expects($this->once()) ->method('setItems') - ->with(['someData']) + ->with([$this->block]) ->willReturnSelf(); - - $this->block->expects($this->once()) - ->method('getData') - ->willReturn(['data']); - - $this->dataHelper->expects($this->once()) - ->method('populateWithArray') - ->with($this->blockData, ['data'], \Magento\Cms\Api\Data\BlockInterface::class); - - $this->dataObjectProcessor->expects($this->once()) - ->method('buildOutputDataArray') - ->with($this->blockData, \Magento\Cms\Api\Data\BlockInterface::class) - ->willReturn('someData'); - $this->assertEquals($this->blockSearchResult, $this->repository->getList($criteria)); } } diff --git a/app/code/Magento/Cms/Test/Unit/Model/PageRepositoryTest.php b/app/code/Magento/Cms/Test/Unit/Model/PageRepositoryTest.php index 7d064c73b3259..1bd742048c51e 100644 --- a/app/code/Magento/Cms/Test/Unit/Model/PageRepositoryTest.php +++ b/app/code/Magento/Cms/Test/Unit/Model/PageRepositoryTest.php @@ -261,22 +261,8 @@ public function testGetList() ->willReturnSelf(); $this->pageSearchResult->expects($this->once()) ->method('setItems') - ->with(['someData']) + ->with([$this->page]) ->willReturnSelf(); - - $this->page->expects($this->once()) - ->method('getData') - ->willReturn(['data']); - - $this->dataHelper->expects($this->once()) - ->method('populateWithArray') - ->with($this->pageData, ['data'], \Magento\Cms\Api\Data\PageInterface::class); - - $this->dataObjectProcessor->expects($this->once()) - ->method('buildOutputDataArray') - ->with($this->pageData, \Magento\Cms\Api\Data\PageInterface::class) - ->willReturn('someData'); - $this->assertEquals($this->pageSearchResult, $this->repository->getList($criteria)); } } diff --git a/app/code/Magento/Config/Model/Config/Backend/Image/Favicon.php b/app/code/Magento/Config/Model/Config/Backend/Image/Favicon.php index 960853778d5f6..1412e0cd77c17 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Image/Favicon.php +++ b/app/code/Magento/Config/Model/Config/Backend/Image/Favicon.php @@ -45,6 +45,6 @@ protected function _addWhetherScopeInfo() */ protected function _getAllowedExtensions() { - return ['ico', 'png', 'gif', 'jpg', 'jpeg', 'apng', 'svg']; + return ['ico', 'png', 'gif', 'jpg', 'jpeg', 'apng']; } } diff --git a/app/code/Magento/Config/Model/Config/Backend/Image/Logo.php b/app/code/Magento/Config/Model/Config/Backend/Image/Logo.php index 908ae53af0991..fc57287fb4945 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Image/Logo.php +++ b/app/code/Magento/Config/Model/Config/Backend/Image/Logo.php @@ -45,6 +45,6 @@ protected function _addWhetherScopeInfo() */ protected function _getAllowedExtensions() { - return ['jpg', 'jpeg', 'gif', 'png', 'svg']; + return ['jpg', 'jpeg', 'gif', 'png']; } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Backend/Image/LogoTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Backend/Image/LogoTest.php index e68cff5d1280d..28f35c233b874 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Backend/Image/LogoTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Backend/Image/LogoTest.php @@ -73,7 +73,7 @@ public function testBeforeSave() ->will($this->returnValue('/tmp/val')); $this->uploaderMock->expects($this->once()) ->method('setAllowedExtensions') - ->with($this->equalTo(['jpg', 'jpeg', 'gif', 'png', 'svg'])); + ->with($this->equalTo(['jpg', 'jpeg', 'gif', 'png'])); $this->model->beforeSave(); } } diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php b/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php index d1794aff97fb9..8f1324195b382 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php @@ -68,8 +68,8 @@ abstract class AbstractFrontend implements \Magento\Eav\Model\Entity\Attribute\F * @param CacheInterface $cache * @param $storeResolver @deprecated * @param array $cacheTags - * @param Serializer $serializer * @param StoreManagerInterface $storeManager + * @param Serializer $serializer * @codeCoverageIgnore * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -78,8 +78,8 @@ public function __construct( CacheInterface $cache = null, $storeResolver = null, array $cacheTags = null, - Serializer $serializer = null, - StoreManagerInterface $storeManager = null + StoreManagerInterface $storeManager = null, + Serializer $serializer = null ) { $this->_attrBooleanFactory = $attrBooleanFactory; $this->cache = $cache ?: ObjectManager::getInstance()->get(CacheInterface::class); diff --git a/app/code/Magento/Eav/Setup/EavSetup.php b/app/code/Magento/Eav/Setup/EavSetup.php index 61146d7e38608..ced56f313dd7d 100644 --- a/app/code/Magento/Eav/Setup/EavSetup.php +++ b/app/code/Magento/Eav/Setup/EavSetup.php @@ -942,6 +942,7 @@ public function updateAttribute($entityTypeId, $id, $field, $value = null, $sort * @param mixed $value * @param int $sortOrder * @return $this + * @throws LocalizedException */ private function _updateAttribute($entityTypeId, $id, $field, $value = null, $sortOrder = null) { @@ -972,11 +973,15 @@ private function _updateAttribute($entityTypeId, $id, $field, $value = null, $so return $this; } } + $attributeId = $this->getAttributeId($entityTypeId, $id); + if (false === $attributeId) { + throw new LocalizedException(__('Attribute with ID: "%1" does not exist', $id)); + } $this->setup->updateTableRow( 'eav_attribute', 'attribute_id', - $this->getAttributeId($entityTypeId, $id), + $attributeId, $field, $value, 'entity_type_id', @@ -994,6 +999,7 @@ private function _updateAttribute($entityTypeId, $id, $field, $value = null, $so * @param string|array $field * @param mixed $value * @return $this + * @throws LocalizedException */ private function _updateAttributeAdditionalData($entityTypeId, $id, $field, $value = null) { @@ -1022,6 +1028,11 @@ private function _updateAttributeAdditionalData($entityTypeId, $id, $field, $val return $this; } } + + $attributeId = $this->getAttributeId($entityTypeId, $id); + if (false === $attributeId) { + throw new LocalizedException(__('Attribute with ID: "%1" does not exist', $id)); + } $this->setup->updateTableRow( $this->setup->getTable($additionalTable), 'attribute_id', diff --git a/app/code/Magento/Email/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Email/view/adminhtml/ui_component/design_config_form.xml index 403abb6fdcade..b63f79233383a 100644 --- a/app/code/Magento/Email/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Email/view/adminhtml/ui_component/design_config_form.xml @@ -22,7 +22,7 @@ - jpg jpeg gif png svg + jpg jpeg gif png 2097152 theme/design_config_fileUploader/save diff --git a/app/code/Magento/GiftMessage/i18n/en_US.csv b/app/code/Magento/GiftMessage/i18n/en_US.csv index 5c82c8e5aeb81..bac6989bd01ae 100644 --- a/app/code/Magento/GiftMessage/i18n/en_US.csv +++ b/app/code/Magento/GiftMessage/i18n/en_US.csv @@ -22,7 +22,7 @@ OK,OK "Gift Options","Gift Options" "Gift Message","Gift Message" "Do you have any gift items in your order?","Do you have any gift items in your order?" -"Add gift options","Add gift options" +"Add Gift Options","Add Gift Options" "Gift Options for the Entire Order","Gift Options for the Entire Order" "Leave this box blank if you don\'t want to leave a gift message for the entire order.","Leave this box blank if you don\'t want to leave a gift message for the entire order." "Gift Options for Individual Items","Gift Options for Individual Items" @@ -30,14 +30,14 @@ OK,OK "Leave a box blank if you don\'t want to add a gift message for that item.","Leave a box blank if you don\'t want to add a gift message for that item." "Add Gift Options for the Entire Order","Add Gift Options for the Entire Order" "You can leave this box blank if you don\'t want to add a gift message for this address.","You can leave this box blank if you don\'t want to add a gift message for this address." -"Add gift options for Individual Items","Add gift options for Individual Items" +"Add Gift Options for Individual Items","Add Gift Options for Individual Items" "You can leave this box blank if you don\'t want to add a gift message for the item.","You can leave this box blank if you don\'t want to add a gift message for the item." "Gift Message (optional)","Gift Message (optional)" To:,To: From:,From: Message:,Message: Update,Update -"Gift options","Gift options" +"Gift Options","Gift Options" Edit,Edit Delete,Delete "Allow Gift Messages on Order Level","Allow Gift Messages on Order Level" diff --git a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml index 8fbb6918d7119..6155cfc37c4ad 100644 --- a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml +++ b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml @@ -14,7 +14,7 @@
getItemsHasMesssages() || $block->getEntityHasMessage()): ?> checked="checked" class="checkbox" /> - +
@@ -148,7 +148,7 @@
getItemsHasMesssages() || $block->getEntityHasMessage()): ?> checked="checked" class="checkbox" /> - +
@@ -197,7 +197,7 @@
getItemsHasMesssages()): ?> checked="checked" class="checkbox" /> - +
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Info.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Info.php index a86d33a9ad762..0ff22646e1935 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Info.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Info.php @@ -303,4 +303,26 @@ public function getFormattedAddress(Address $address) { return $this->addressRenderer->format($address, 'html'); } + + /** + * @inheritdoc + */ + public function getChildHtml($alias = '', $useCache = true) + { + $layout = $this->getLayout(); + + if ($alias || !$layout) { + return parent::getChildHtml($alias, $useCache); + } + + $childNames = $layout->getChildNames($this->getNameInLayout()); + $outputChildNames = array_diff($childNames, ['extra_customer_info']); + + $out = ''; + foreach ($outputChildNames as $childName) { + $out .= $layout->renderElement($childName, $useCache); + } + + return $out; + } } diff --git a/app/code/Magento/SendFriend/view/frontend/layout/sendfriend_product_send.xml b/app/code/Magento/SendFriend/view/frontend/layout/sendfriend_product_send.xml index 2d404cb96f97f..8065b7e236132 100644 --- a/app/code/Magento/SendFriend/view/frontend/layout/sendfriend_product_send.xml +++ b/app/code/Magento/SendFriend/view/frontend/layout/sendfriend_product_send.xml @@ -13,7 +13,9 @@ - + + + diff --git a/app/code/Magento/SendFriend/view/frontend/templates/send.phtml b/app/code/Magento/SendFriend/view/frontend/templates/send.phtml index a2bc20e1a2816..b953c6e9ea0d9 100644 --- a/app/code/Magento/SendFriend/view/frontend/templates/send.phtml +++ b/app/code/Magento/SendFriend/view/frontend/templates/send.phtml @@ -104,6 +104,7 @@
+ getChildHtml('form_additional_info'); ?>
diff --git a/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml index 18b4246d58f37..66626add3f671 100644 --- a/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml @@ -22,7 +22,7 @@ - jpg jpeg gif png svg + jpg jpeg gif png 2097152 theme/design_config_fileUploader/save diff --git a/app/code/Magento/Tax/Setup/RecurringData.php b/app/code/Magento/Tax/Setup/RecurringData.php new file mode 100644 index 0000000000000..bc05db428cde8 --- /dev/null +++ b/app/code/Magento/Tax/Setup/RecurringData.php @@ -0,0 +1,92 @@ +taxRateRepository = $taxRateRepository; + $this->searchCriteriaFactory = $searchCriteriaFactory; + $this->directoryRegionFactory = $directoryRegionFactory; + } + + /** + * {@inheritdoc} + */ + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $taxRateList = $this->taxRateRepository->getList($this->searchCriteriaFactory->create()); + /** @var \Magento\Tax\Api\Data\TaxRateInterface $taxRateData */ + foreach ($taxRateList->getItems() as $taxRateData) { + $regionCode = $this->parseRegionFromTaxCode($taxRateData->getCode()); + if ($regionCode) { + /** @var \Magento\Directory\Model\Region $region */ + $region = $this->directoryRegionFactory->create(); + $region->loadByCode($regionCode, $taxRateData->getTaxCountryId()); + $taxRateData->setTaxRegionId($region->getRegionId()); + $this->taxRateRepository->save($taxRateData); + } + } + } + + /** + * Parse region code from tax code + * + * @param string $taxCode + * @return string + */ + private function parseRegionFromTaxCode($taxCode) + { + $result = ''; + $parts = explode('-', $taxCode, 3); + + if (isset($parts[1])) { + $result = $parts[1]; + } + + return $result; + } +} diff --git a/app/code/Magento/Theme/Model/Design/Backend/Favicon.php b/app/code/Magento/Theme/Model/Design/Backend/Favicon.php index 160642818cfbd..2d53b11eea6cb 100644 --- a/app/code/Magento/Theme/Model/Design/Backend/Favicon.php +++ b/app/code/Magento/Theme/Model/Design/Backend/Favicon.php @@ -43,6 +43,6 @@ protected function _addWhetherScopeInfo() */ public function getAllowedExtensions() { - return ['ico', 'png', 'gif', 'jpg', 'jpeg', 'apng', 'svg']; + return ['ico', 'png', 'gif', 'jpg', 'jpeg', 'apng']; } } diff --git a/app/code/Magento/Theme/Model/Design/Backend/Logo.php b/app/code/Magento/Theme/Model/Design/Backend/Logo.php index 88a1317d74b78..e5652d7ee4007 100644 --- a/app/code/Magento/Theme/Model/Design/Backend/Logo.php +++ b/app/code/Magento/Theme/Model/Design/Backend/Logo.php @@ -41,6 +41,6 @@ protected function _addWhetherScopeInfo() */ public function getAllowedExtensions() { - return ['jpg', 'jpeg', 'gif', 'png', 'svg']; + return ['jpg', 'jpeg', 'gif', 'png']; } } diff --git a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml index c89c25e1a324a..20625842a7274 100644 --- a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml @@ -56,14 +56,14 @@ - Allowed file types: ico, png, gif, jpg, jpeg, apng, svg. Not all browsers support all these formats! + Allowed file types: ico, png, gif, jpg, jpeg, apng. Not all browsers support all these formats! fileUploader - jpg jpeg gif png svg ico apng + jpg jpeg gif png ico apng 2097152 theme/design_config_fileUploader/save @@ -153,14 +153,14 @@ - Allowed file types: png, gif, jpg, jpeg, svg. + Allowed file types: png, gif, jpg, jpeg. fileUploader - jpg jpeg gif png svg + jpg jpeg gif png 2097152 theme/design_config_fileUploader/save diff --git a/composer.json b/composer.json index 79b44a9ae2e38..08b921abcd650 100644 --- a/composer.json +++ b/composer.json @@ -68,6 +68,7 @@ "ext-openssl": "*", "ext-zip": "*", "ext-pdo_mysql": "*", + "ext-soap": "*", "sjparkinson/static-review": "~4.1", "ramsey/uuid": "3.6.1" }, diff --git a/composer.lock b/composer.lock index 8b56f72d8d650..845d2bbf5576d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "f6383328a3387e72091eddc2ed464cd1", - "content-hash": "466e4d122888ecfdcc9705c880a4dd69", + "hash": "943975c96428352b445c2636c6c53e9b", + "content-hash": "c7ae72ad7777ba197d1ba038a50df230", "packages": [ { "name": "braintree/braintree_php", @@ -5449,7 +5449,8 @@ "ext-mbstring": "*", "ext-openssl": "*", "ext-zip": "*", - "ext-pdo_mysql": "*" + "ext-pdo_mysql": "*", + "ext-soap": "*" }, "platform-dev": [] } diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/OrderInvoiceCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/OrderInvoiceCreateTest.php new file mode 100644 index 0000000000000..3a40e510326a4 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/OrderInvoiceCreateTest.php @@ -0,0 +1,143 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->invoiceRepository = $this->objectManager->get( + \Magento\Sales\Api\InvoiceRepositoryInterface::class + ); + } + + /** + * Test create a partial invoice for order with bundle and Simple products. + * + * @return void + * @magentoApiDataFixture Magento/Bundle/_files/order_items_simple_and_bundle.php + */ + public function testInvoiceWithSimpleAndBundleCreate() + { + /** @var \Magento\Sales\Api\Data\OrderInterface $existingOrder*/ + $existingOrder = $this->objectManager->create(\Magento\Sales\Api\Data\OrderInterface::class) + ->loadByIncrementId('100000001'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/invoice', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'execute', + ], + ]; + + $requestData = [ + 'orderId' => $existingOrder->getId(), + 'items' => [], + 'comment' => [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1, + ], + ]; + $grantTotal = 0; + foreach ($existingOrder->getAllItems() as $item) { + $requestData['items'] = []; + $requestData['items'][] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + try { + $invoice = $this->invoiceRepository->get($result); + $grantTotal += $invoice->getGrandTotal(); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->fail('Failed asserting that Invoice was created'); + } + } + $this->assertNotEquals( + $existingOrder->getGrandTotal(), + $grantTotal, + 'Failed asserting that invoice is correct.' + ); + } + + /** + * Test create invoice with Bundle product. + * + * @return void + * @magentoApiDataFixture Magento/Bundle/_files/order_item_with_bundle_and_options.php + */ + public function testInvoiceWithBundleCreate() + { + /** @var \Magento\Sales\Api\Data\OrderInterface $existingOrder*/ + $existingOrder = $this->objectManager->create(\Magento\Sales\Api\Data\OrderInterface::class) + ->loadByIncrementId('100000001'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/invoice', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'execute', + ], + ]; + + $requestData = [ + 'orderId' => $existingOrder->getId(), + 'items' => [], + 'comment' => [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1, + ], + ]; + + /** @var \Magento\Sales\Api\Data\OrderItemInterface $item */ + foreach ($existingOrder->getAllItems() as $item) { + $requestData['items'][] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ]; + } + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + $invoice = $this->invoiceRepository->get($result); + $this->assertNotEquals( + $existingOrder->getGrandTotal(), + $invoice->getGrandTotal(), + 'Failed asserting that invoice is correct.' + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing.php index 7aeb5c1e238d9..bc64f6ab6f23d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing.php @@ -10,6 +10,7 @@ use Magento\Mtf\Client\Element\SimpleElement; use Magento\Ui\Test\Block\Adminhtml\Section; use Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Options\AbstractOptions; +use Magento\Mtf\Client\Locator; /** * Product advanced pricing section. @@ -37,6 +38,13 @@ class AdvancedPricing extends Section */ protected $doneButton = '.action-primary[data-role="action"]'; + /** + * Selector for field. + * + * @var string + */ + private $fieldByName = '//*[contains(text(),"%s")]/preceding::div[2]/ancestor::div[1]'; + /** * Fill 'Advanced price' product form on tab. * @@ -104,4 +112,15 @@ public function getTierPriceForm(SimpleElement $element = null) ['element' => $element] ); } + + /** + * Check if the field is displayed correctly. + * + * @param string $fieldName + * @return bool + */ + public function checkField($fieldName) + { + return $this->_rootElement->find(sprintf($this->fieldByName, $fieldName), Locator::SELECTOR_XPATH)->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php index e6a7f60bcec0d..ebd455fa1ed93 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php @@ -28,6 +28,7 @@ class ClearAllCompareProductsTest extends AbstractCompareProductsTest { /* tags */ const MVP = 'yes'; + const TEST_TYPE = 'extended_acceptance_test'; /* end tags */ /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml index 1a702147b40f4..523156fb0de74 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml @@ -8,7 +8,6 @@ - stable:no compare_products catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php index 9f0c6cb6f3a27..10299486a08ce 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php @@ -37,7 +37,7 @@ class Shipping extends Form protected $shippingMethod = '//span[text()="%s"]/following::label[contains(., "%s")]/../input'; /** - * From with shipping available shipping methods. + * Form with shipping available shipping methods. * * @var string */ diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php new file mode 100644 index 0000000000000..a9860ab7b7715 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php @@ -0,0 +1,51 @@ +open(['id' => $product->getId()]); + $catalogProductEdit->getProductForm()->openSection('advanced-pricing'); + $advancedPricing = $catalogProductEdit->getProductForm()->getSection('advanced-pricing'); + + \PHPUnit_Framework_Assert::assertTrue( + $advancedPricing->checkField($this->manufacturerFieldTitle), + '"Manufacturer\'s Suggested Retail Price" field is not correct.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return '"Manufacturer\'s Suggested Retail Price" field is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.xml index a5efdc3d5e917..32d86dec7a52a 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.xml @@ -46,5 +46,9 @@ + + bundleProduct::bundle_fixed_product + + diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_items_simple_and_bundle.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_items_simple_and_bundle.php new file mode 100644 index 0000000000000..8ca201225f842 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_items_simple_and_bundle.php @@ -0,0 +1,23 @@ +create(\Magento\Sales\Model\Order\Item::class); +/** @var $product \Magento\Catalog\Model\Product */ +$orderItem->setProductId($product->getId())->setQtyOrdered(1); +$orderItem->setBasePrice($product->getPrice()); +$orderItem->setPrice($product->getPrice()); +$orderItem->setRowTotal($product->getPrice()); +$orderItem->setProductType('simple'); + +/** @var \Magento\Sales\Model\Order $order */ +$order->addItem($orderItem); +$order->save(); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_items_simple_and_bundle_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_items_simple_and_bundle_rollback.php new file mode 100644 index 0000000000000..a3b4dd410913f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_items_simple_and_bundle_rollback.php @@ -0,0 +1,9 @@ +assertResults($categoryExpectedResult, $actualResults); + + /** @var \Magento\Catalog\Model\ProductRepository $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Model\ProductRepository::class); + $product = $productRepository->get('12345'); + $productForTest = $product->getId(); + + $productFilter = [ + UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, + UrlRewrite::ENTITY_ID => [$productForTest] + ]; + $actualResults = $this->getActualResults($productFilter); + $productExpectedResult = [ + [ + 'simple-product-two.html', + 'catalog/product/view/id/' . $productForTest, + 1, + 0 + ], + [ + 'new-url/category-1-1/category-1-1-1/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/5', + 1, + 0 + ], + [ + 'new-url/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/3', + 1, + 0 + ], + [ + 'new-url/category-1-1/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/4', + 1, + 0 + ], + [ + '/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/2', + 1, + 0 + ] + ]; + + $this->assertResults($productExpectedResult, $actualResults); } /** * @magentoDbIsolation enabled - * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories_with_products.php * @magentoAppIsolation enabled */ public function testGenerateUrlRewritesWithSaveHistory() @@ -86,6 +132,69 @@ public function testGenerateUrlRewritesWithSaveHistory() ]; $this->assertResults($categoryExpectedResult, $actualResults); + + /** @var \Magento\Catalog\Model\ProductRepository $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Model\ProductRepository::class); + $product = $productRepository->get('12345'); + $productForTest = $product->getId(); + + $productFilter = [ + UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, + UrlRewrite::ENTITY_ID => [$productForTest] + ]; + $actualResults = $this->getActualResults($productFilter); + $productExpectedResult = [ + [ + 'simple-product-two.html', + 'catalog/product/view/id/' . $productForTest, + 1, + 0 + ], + [ + 'new-url/category-1-1/category-1-1-1/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/5', + 1, + 0 + ], + [ + 'category-1/category-1-1/category-1-1-1/simple-product-two.html', + 'new-url/category-1-1/category-1-1-1/simple-product-two.html', + 0, + OptionProvider::PERMANENT + ], + [ + 'new-url/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/3', + 1, + 0 + ], + [ + 'new-url/category-1-1/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/4', + 1, + 0 + ], + [ + '/simple-product-two.html', + 'catalog/product/view/id/' . $productForTest . '/category/2', + 1, + 0 + ], + [ + 'category-1/simple-product-two.html', + 'new-url/simple-product-two.html', + 0, + OptionProvider::PERMANENT + ], + [ + 'category-1/category-1-1/simple-product-two.html', + 'new-url/category-1-1/simple-product-two.html', + 0, + OptionProvider::PERMANENT + ], + ]; + + $this->assertResults($productExpectedResult, $actualResults); } /** @@ -145,6 +254,7 @@ protected function getActualResults(array $filter) */ protected function assertResults($expected, $actual) { + $this->assertEquals(count($expected), count($actual), 'Number of rewrites does not match'); foreach ($expected as $row) { $this->assertContains( $row, diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index 58d510afbd931..ff5afe939d133 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -64,6 +64,38 @@ public function testLogoutAction() $this->assertRedirect($this->stringContains('customer/account/logoutSuccess')); } + /** + * Test that forgot password email message displays special characters correctly. + * + * @magentoConfigFixture current_store customer/password/limit_password_reset_requests_method 0 + * @magentoConfigFixture current_store customer/password/forgot_email_template customer_password_forgot_email_template + * @magentoConfigFixture current_store customer/password/forgot_email_identity support + * @magentoConfigFixture current_store general/store_information/name Test special' characters + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testForgotPasswordEmailMessageWithSpecialCharacters() + { + $email = 'customer@example.com'; + + $this->getRequest() + ->setPostValue([ + 'email' => $email, + ]); + + $this->dispatch('customer/account/forgotPasswordPost'); + $this->assertRedirect($this->stringContains('customer/account/')); + + /** @var \Magento\TestFramework\Mail\Template\TransportBuilderMock $transportBuilder */ + $transportBuilder = $this->_objectManager->get( + \Magento\TestFramework\Mail\Template\TransportBuilderMock::class + ); + $subject = $transportBuilder->getSentMessage()->getSubject(); + $this->assertContains( + 'Test special\' characters', + $subject + ); + } + /** * @magentoDataFixture Magento/Customer/_files/customer.php */ diff --git a/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php b/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php new file mode 100644 index 0000000000000..d67825ea6ec8f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php @@ -0,0 +1,46 @@ +_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test that GetTargetStorePostData() method return correct store URL. + * + * @magentoDataFixture Magento/Store/_files/store.php + * @return void + */ + public function testGetTargetStorePostData() + { + $storeCode = 'test'; + /** @var \Magento\Store\Block\Switcher $block */ + $block = $this->_objectManager->create(\Magento\Store\Block\Switcher::class); + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->_objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $store = $storeRepository->get($storeCode); + $result = json_decode($block->getTargetStorePostData($store), true); + + $this->assertContains($storeCode, $result['action']); + } +} diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/paypal/button.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/paypal/button.test.js new file mode 100644 index 0000000000000..a4767fb551ee3 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/paypal/button.test.js @@ -0,0 +1,85 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint-disable max-nested-callbacks */ +define([ + 'squire', + 'jquery' +], function (Squire) { + 'use strict'; + + describe('Magento_Braintree/js/paypal/button', function () { + var injector, + mocks, + braintree, + component, + registry, + btnId = 'braintree_paypal_btn', + tplElement = jQuery('')[0]; + + require.config({ + map: { + '*': { + 'braintree': 'braintree' + } + } + }); + + injector = new Squire(); + mocks = { + 'braintree': { + paypal: { + /** Stub */ + initAuthFlow: function () {} + }, + + /** Stub */ + setup: function () {} + } + }; + + beforeEach(function (done) { + injector.mock(mocks); + + injector.require([ + 'braintree', + 'uiRegistry', + 'Magento_Braintree/js/paypal/button' + ], function (adapter, reg, Constr) { + braintree = adapter; + registry = reg; + jQuery(document.body).append(tplElement); + + spyOn(braintree, 'setup').and.callFake(function () { + registry.set('braintreePaypal.currentIntegration', braintree); + jQuery('#' + btnId).removeAttr('disabled'); + }); + + component = new Constr({ + id: btnId + }); + done(); + }); + }); + + afterAll(function (done) { + tplElement.remove(); + registry.remove(component.integrationName); + done(); + }); + + it('The PayPal::initAuthFlow throws an exception.', function () { + var $selector = jQuery('#' + component.id); + + spyOn(braintree.paypal, 'initAuthFlow').and.callFake(function () { + throw new TypeError('Cannot read property of undefined'); + }); + + $selector.trigger('click'); + + expect($selector.prop('disabled')).toEqual(true); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js new file mode 100644 index 0000000000000..a9987f5e01ba8 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js @@ -0,0 +1,79 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint-disable max-nested-callbacks */ +define([ + 'squire', + 'ko' +], function (Squire, ko) { + 'use strict'; + + describe('Magento_Braintree/js/view/payment/method-renderer/paypal', function () { + + var injector = new Squire(), + mocks = { + 'Magento_Checkout/js/model/quote': { + billingAddress: ko.observable(), + shippingAddress: ko.observable({ + postcode: '', + street: [], + canUseForBilling: ko.observable() + }), + paymentMethod: ko.observable(), + totals: ko.observable({ + 'base_grand_total': 0 + }) + }, + 'Magento_Braintree/js/view/payment/adapter': { + checkout: { + paypal: { + /** Stub */ + initAuthFlow: function () {} + } + } + } + }, + braintreeAdapter, + component, + additionalValidator; + + beforeEach(function (done) { + window.checkoutConfig = { + quoteData: {}, + payment: { + 'braintree_paypal': { + title: 'Braintree PayPal' + } + }, + vault: {} + }; + + injector.mock(mocks); + + injector.require([ + 'Magento_Braintree/js/view/payment/adapter', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Braintree/js/view/payment/method-renderer/paypal' + ], function (adapter, validator, Constr) { + braintreeAdapter = adapter; + additionalValidator = validator; + component = new Constr(); + done(); + }); + }); + + it('The PayPal::initAuthFlow throws an exception.', function () { + + spyOn(additionalValidator, 'validate').and.returnValue(true); + spyOn(braintreeAdapter.checkout.paypal, 'initAuthFlow').and.callFake(function () { + throw new TypeError('Cannot read property of undefined'); + }); + spyOn(component.messageContainer, 'addErrorMessage'); + + component.payWithPayPal(); + expect(component.messageContainer.addErrorMessage).toHaveBeenCalled(); + }); + }); +}); diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php index 001d7b1327dcc..c856296102095 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php @@ -10,15 +10,121 @@ */ class ComposerLockTest extends \PHPUnit_Framework_TestCase { - public function testUpToDate() + /** + * @return string + */ + public function testLockFileExists() { - $hash = hash_file('md5', BP . '/composer.json'); $lockFilePath = BP . '/composer.lock'; - if (!file_exists($lockFilePath)) { - $this->markTestSkipped('composer.lock file doesn\'t exist'); + $this->assertLockFileExists($lockFilePath); + return $lockFilePath; + } + + /** + * @depends testLockFileExists + * @param string $lockFilePath + * @return string + */ + public function testLockFileReadable($lockFilePath) + { + $this->assertLockFileReadable($lockFilePath); + return $lockFilePath; + } + + /** + * @depends testLockFileReadable + * @param string $lockFilePath + * @return string + */ + public function testLockFileContainsJson($lockFilePath) + { + $lockFileContent = file_get_contents($lockFilePath); + $this->assertLockFileContainsValidJson($lockFileContent); + return $lockFileContent; + } + + /** + * @depends testLockFileContainsJson + * @param string $lockFileContent + */ + public function testUpToDate($lockFileContent) + { + $lockData = json_decode($lockFileContent, true); + $composerFilePath = BP . '/composer.json'; + $this->assertLockDataRelevantToComposerFile($lockData, $composerFilePath); + } + + /** + * @param string $lockFilePath + */ + private function assertLockFileExists($lockFilePath) + { + $this->assertFileExists($lockFilePath, 'composer.lock file does not exist'); + } + + /** + * @param string $lockFilePath + */ + private function assertLockFileReadable($lockFilePath) + { + if (!is_readable($lockFilePath)) { + $this->fail('composer.lock file is not readable'); } - $jsonData = file_get_contents($lockFilePath); - $json = json_decode($jsonData); - $this->assertSame($hash, $json->hash, 'composer.lock file is not up to date'); + } + + /** + * @param string $lockFileContent + */ + private function assertLockFileContainsValidJson($lockFileContent) + { + $this->assertJson($lockFileContent, 'composer.lock file does not contains valid json'); + } + + /** + * @param array $lockData + * @param string $composerFilePath + */ + private function assertLockDataRelevantToComposerFile(array $lockData, $composerFilePath) + { + if (isset($lockData['content-hash'])) { + $this->assertLockDataRelevantToMeaningfulComposerConfig($lockData, $composerFilePath); + } else if (isset($lockData['hash'])) { + $this->assertLockDataRelevantToFullComposerConfig($lockData, $composerFilePath); + } else { + $this->fail('composer.lock does not linked to composer.json data'); + } + } + + /** + * @param array $lockData + * @param string $composerFilePath + */ + private function assertLockDataRelevantToMeaningfulComposerConfig(array $lockData, $composerFilePath) + { + $contentHashCalculator = 'Composer\Package\Locker::getContentHash'; + if (!is_callable($contentHashCalculator)) { + $this->markTestSkipped('Unable to check composer.lock file by content hash'); + } + + $composerContentHash = call_user_func($contentHashCalculator, file_get_contents($composerFilePath)); + $this->assertSame( + $composerContentHash, + $lockData['content-hash'], + 'composer.lock file is not up to date (composer.json file was modified)' + ); + } + + /** + * @param array $lockData + * @param string $composerFilePath + */ + private function assertLockDataRelevantToFullComposerConfig(array $lockData, $composerFilePath) + { + $composerFileHash = hash_file('md5', $composerFilePath); + $this->assertSame( + $composerFileHash, + $lockData['hash'], + 'composer.lock file is not up to date (composer.json file was modified)' + ); } } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php index e6a036487fc5a..04e440154e96c 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php @@ -99,7 +99,12 @@ private function validateComposerJsonFile($path) /** @var \Magento\Framework\Composer\MagentoComposerApplicationFactory $appFactory */ $appFactory = self::$objectManager->get(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class); $app = $appFactory->create(); - $app->runComposerCommand(['command' => 'validate'], $path); + + try { + $app->runComposerCommand(['command' => 'validate'], $path); + } catch (\RuntimeException $exception) { + $this->fail($exception->getMessage()); + } } /** diff --git a/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php b/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php index 5882f8c7af6ff..db466ca30e7eb 100644 --- a/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php +++ b/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php @@ -173,12 +173,14 @@ public function write($method, $url, $http_ver = '1.1', $headers = [], $body = ' curl_setopt($this->_getResource(), CURLOPT_RETURNTRANSFER, true); if ($method == \Zend_Http_Client::POST) { curl_setopt($this->_getResource(), CURLOPT_POST, true); + curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($this->_getResource(), CURLOPT_POSTFIELDS, $body); - } elseif ($method == \Zend_Http_Client::GET) { - curl_setopt($this->_getResource(), CURLOPT_HTTPGET, true); } elseif ($method == \Zend_Http_Client::PUT) { - curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, \Zend_Http_Client::PUT); + curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($this->_getResource(), CURLOPT_POSTFIELDS, $body); + } elseif ($method == \Zend_Http_Client::GET) { + curl_setopt($this->_getResource(), CURLOPT_HTTPGET, true); + curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, 'GET'); } if (is_array($headers)) { diff --git a/lib/internal/Magento/Framework/Validator/Builder.php b/lib/internal/Magento/Framework/Validator/Builder.php index b50c729c3973e..41be9346251ce 100644 --- a/lib/internal/Magento/Framework/Validator/Builder.php +++ b/lib/internal/Magento/Framework/Validator/Builder.php @@ -6,8 +6,6 @@ * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - namespace Magento\Framework\Validator; use Magento\Framework\Validator\Constraint\OptionInterface; @@ -257,7 +255,11 @@ protected function _createConstraint(array $data) } if (\Magento\Framework\Validator\Config::CONSTRAINT_TYPE_PROPERTY == $data['type']) { - $result = new \Magento\Framework\Validator\Constraint\Property($validator, $data['property'], $data['alias']); + $result = new \Magento\Framework\Validator\Constraint\Property( + $validator, + $data['property'], + $data['alias'] + ); } else { $result = $this->_constraintFactory->create(['validator' => $validator, 'alias' => $data['alias']]); } @@ -286,7 +288,10 @@ protected function _createConstraintValidator(array $data) // Check validator type if (!$validator instanceof \Magento\Framework\Validator\ValidatorInterface) { throw new \InvalidArgumentException( - sprintf('Constraint class "%s" must implement \Magento\Framework\Validator\ValidatorInterface', $data['class']) + sprintf( + 'Constraint class "%s" must implement \Magento\Framework\Validator\ValidatorInterface', + $data['class'] + ) ); } @@ -300,8 +305,10 @@ protected function _createConstraintValidator(array $data) * @param array $options * @return void */ - protected function _configureConstraintValidator(\Magento\Framework\Validator\ValidatorInterface $validator, array $options) - { + protected function _configureConstraintValidator( + \Magento\Framework\Validator\ValidatorInterface $validator, + array $options + ) { // Call all validator methods according to configuration if (isset($options['methods'])) { foreach ($options['methods'] as $methodData) { diff --git a/lib/internal/Magento/Framework/Validator/Constraint/Property.php b/lib/internal/Magento/Framework/Validator/Constraint/Property.php index a209e00f738e8..f4842e15ea32e 100644 --- a/lib/internal/Magento/Framework/Validator/Constraint/Property.php +++ b/lib/internal/Magento/Framework/Validator/Constraint/Property.php @@ -6,8 +6,6 @@ * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - namespace Magento\Framework\Validator\Constraint; class Property extends \Magento\Framework\Validator\Constraint @@ -33,8 +31,8 @@ public function __construct(\Magento\Framework\Validator\ValidatorInterface $val } /** - * Get value that should be validated. Tries to extract value's property if \Magento\Framework\DataObject or \ArrayAccess or array - * is passed + * Get value that should be validated. Tries to extract value's property if \Magento\Framework\DataObject or + * \ArrayAccess or array is passed * * @param mixed $value * @return mixed diff --git a/lib/internal/Magento/Framework/Validator/ConstraintFactory.php b/lib/internal/Magento/Framework/Validator/ConstraintFactory.php index 43d3ef3d9cb35..d90c4ee47338a 100644 --- a/lib/internal/Magento/Framework/Validator/ConstraintFactory.php +++ b/lib/internal/Magento/Framework/Validator/ConstraintFactory.php @@ -4,8 +4,6 @@ * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - /** * Factory class for \Magento\Framework\Validator\Constraint */ @@ -33,8 +31,10 @@ class ConstraintFactory * @param \Magento\Framework\ObjectManagerInterface $objectManager * @param string $instanceName */ - public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, $instanceName = \Magento\Framework\Validator\Constraint::class) - { + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = \Magento\Framework\Validator\Constraint::class + ) { $this->_objectManager = $objectManager; $this->_instanceName = $instanceName; } diff --git a/lib/internal/Magento/Framework/Validator/Factory.php b/lib/internal/Magento/Framework/Validator/Factory.php index a1b1752d5ded1..c7df8547fb4b3 100644 --- a/lib/internal/Magento/Framework/Validator/Factory.php +++ b/lib/internal/Magento/Framework/Validator/Factory.php @@ -3,18 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\Validator; use Magento\Framework\Cache\FrontendInterface; -/** - * @codingStandardsIgnoreFile - */ class Factory { - /** - * Cache key - */ + /** cache key */ const CACHE_KEY = __CLASS__; /** @@ -73,6 +69,8 @@ public function __construct( /** * Init cached list of validation files + * + * @return void */ protected function _initializeConfigList() { @@ -80,7 +78,10 @@ protected function _initializeConfigList() $this->_configFiles = $this->cache->load(self::CACHE_KEY); if (!$this->_configFiles) { $this->_configFiles = $this->moduleReader->getConfigurationFiles('validation.xml'); - $this->cache->save($this->getSerializer()->serialize($this->_configFiles->toArray()), self::CACHE_KEY); + $this->cache->save( + $this->getSerializer()->serialize($this->_configFiles->toArray()), + self::CACHE_KEY + ); } else { $filesArray = $this->getSerializer()->unserialize($this->_configFiles); $this->_configFiles = $this->getFileIteratorFactory()->create(array_keys($filesArray)); @@ -121,7 +122,9 @@ public function getValidatorConfig() $this->_initializeConfigList(); $this->_initializeDefaultTranslator(); return $this->_objectManager->create( - \Magento\Framework\Validator\Config::class, ['configFiles' => $this->_configFiles]); + \Magento\Framework\Validator\Config::class, + ['configFiles' => $this->_configFiles] + ); } /** @@ -161,7 +164,9 @@ public function createValidator($entityName, $groupName, array $builderConfig = private function getSerializer() { if ($this->serializer === null) { - $this->serializer = $this->_objectManager->get(\Magento\Framework\Serialize\SerializerInterface::class); + $this->serializer = $this->_objectManager->get( + \Magento\Framework\Serialize\SerializerInterface::class + ); } return $this->serializer; } @@ -175,8 +180,9 @@ private function getSerializer() private function getFileIteratorFactory() { if ($this->fileIteratorFactory === null) { - $this->fileIteratorFactory = $this->_objectManager - ->get(\Magento\Framework\Config\FileIteratorFactory::class); + $this->fileIteratorFactory = $this->_objectManager->get( + \Magento\Framework\Config\FileIteratorFactory::class + ); } return $this->fileIteratorFactory; } diff --git a/lib/internal/Magento/Framework/View/Element/Html/Calendar.php b/lib/internal/Magento/Framework/View/Element/Html/Calendar.php index 8bfa611466ac4..0c8187569cf28 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Calendar.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Calendar.php @@ -78,14 +78,31 @@ protected function _toHtml() ] ); - // get months names + /** + * Month names in abbreviated format values was added to ICU Data tables + * starting ICU library version 52.1. For some OS, like CentOS, default + * installation version of ICU library is 50.1.2, which not contain + * 'abbreviated' key, and that may cause a PHP fatal error when passing + * as an argument of function 'iterator_to_array'. This issue affects + * locales like ja_JP, ko_KR etc. + * + * @see http://source.icu-project.org/repos/icu/tags/release-50-1-2/icu4c/source/data/locales/ja.txt + * @see http://source.icu-project.org/repos/icu/tags/release-52-1/icu4c/source/data/locales/ja.txt + * @var \ResourceBundle $monthsData + */ $monthsData = $localeData['calendar']['gregorian']['monthNames']; $this->assign( 'months', [ 'wide' => $this->encoder->encode(array_values(iterator_to_array($monthsData['format']['wide']))), 'abbreviated' => $this->encoder->encode( - array_values(iterator_to_array($monthsData['format']['abbreviated'])) + array_values( + iterator_to_array( + null !== $monthsData->get('format')->get('abbreviated') + ? $monthsData['format']['abbreviated'] + : $monthsData['format']['wide'] + ) + ) ), ] ); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/CalendarTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/CalendarTest.php index d5a9adb80a84a..36e16499ca763 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/CalendarTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/CalendarTest.php @@ -5,49 +5,92 @@ */ namespace Magento\Framework\View\Test\Unit\Element\Html; +use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\View\Element\Html\Calendar; +use Magento\Framework\View\Element\Template\Context; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +/** + * @see Calendar + */ class CalendarTest extends \PHPUnit_Framework_TestCase { /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + * @see MAGETWO-60828 + * @see Calendar::_toHtml + * + * @param string $locale + * @dataProvider localesDataProvider */ - protected $objectManagerHelper; - - /** @var \Magento\Framework\View\Element\Html\Calendar */ - protected $block; - - /** @var \Magento\Framework\View\Element\Template\Context */ - protected $context; + public function testToHtmlWithDifferentLocales($locale) + { + $calendarBlock = (new ObjectManager($this))->getObject( + Calendar::class, + [ + 'localeResolver' => $this->getLocalResolver($locale) + ] + ); - /** @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $localeDate; + $calendarBlock->toHtml(); + } - protected function setUp() + /** + * @return array + */ + public function localesDataProvider() { - $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->localeDate = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) - ->getMock(); + return [ + ['en_US'], + ['ja_JP'], + ['ko_KR'], + ]; + } - /** @var \Magento\Framework\View\Element\Template\Context $context */ - $this->context = $this->objectManagerHelper->getObject( - \Magento\Framework\View\Element\Template\Context::class, + /** + * @see Calendar::getYearRange + */ + public function testGetYearRange() + { + $calendarBlock = (new ObjectManager($this))->getObject( + Calendar::class, [ - 'localeDate' => $this->localeDate, + 'context' => $this->getContext() ] ); - /** @var \Magento\Framework\View\Element\Html\Links $block */ - $this->block = $this->objectManagerHelper->getObject( - \Magento\Framework\View\Element\Html\Calendar::class, - ['context' => $this->context] + $testCurrentYear = (new \DateTime())->format('Y'); + $this->assertEquals( + (int) $testCurrentYear - 100 . ':' . ($testCurrentYear + 100), + $calendarBlock->getYearRange() ); } /** - * @test + * @param string $locale + * @return ResolverInterface|MockObject */ - public function testGetYearRange() + private function getLocalResolver($locale) { - $testCurrentYear = (new \DateTime())->format('Y'); - $this->assertEquals((int)$testCurrentYear - 100 . ':' . ($testCurrentYear + 100), $this->block->getYearRange()); + $localResolver = $this->getMockBuilder(ResolverInterface::class) + ->getMockForAbstractClass(); + $localResolver->method('getLocale')->willReturn($locale); + + return $localResolver; + } + + /** + * @return Context|Object + */ + private function getContext() + { + $localeDate = $this->getMockBuilder(TimezoneInterface::class) + ->getMockForAbstractClass(); + + return (new ObjectManager($this))->getObject( + Context::class, + ['localeDate' => $localeDate] + ); } } diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js index aa0b19f5f11a2..f2b3365555f3c 100755 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js @@ -463,8 +463,6 @@ define([ var url = this.makeDirectiveUrl('%directive%').replace(/([$^.?*!+:=()\[\]{}|\\])/g, '\\$1'), reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9,_-]+)')); - content = decodeURIComponent(content); - return content.gsub(reg, function (match) { //eslint-disable-line no-extra-bind return Base64.mageDecode(match[1]); }); diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php b/setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php index f04a78f7d957b..a757cda7ba79a 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php @@ -80,11 +80,17 @@ public function add($type, $key, $message = '') * Write entries * * @return void + * @throws \Magento\Framework\Validator\Exception */ public function report() { $this->_successWriter->write($this->_successEntries); $this->_errorWriter->write($this->_errorEntries); + //do not take into account empty items since they are initialized in constructor. + $errors = array_filter($this->_errorEntries); + if (count($errors) > 0) { + throw new \Magento\Framework\Validator\Exception(__('Error during compilation')); + } } /** diff --git a/setup/view/magento/setup/marketplace-credentials.phtml b/setup/view/magento/setup/marketplace-credentials.phtml index 22ad4b6558f33..c13517f2200ee 100644 --- a/setup/view/magento/setup/marketplace-credentials.phtml +++ b/setup/view/magento/setup/marketplace-credentials.phtml @@ -23,6 +23,7 @@
@@ -63,6 +64,7 @@ || (auth.username.$error.required && user.submitted) }" autofocus required + autocomplete="off" >
This is a required field. @@ -84,6 +86,7 @@ && !auth.password.$pristine) || (auth.password.$error.required && user.submitted) }" required + autocomplete="new-password" >
This is a required field. diff --git a/setup/view/magento/setup/popupauth.phtml b/setup/view/magento/setup/popupauth.phtml index 87263c7247461..bce55a7c336dc 100644 --- a/setup/view/magento/setup/popupauth.phtml +++ b/setup/view/magento/setup/popupauth.phtml @@ -32,6 +32,7 @@
@@ -62,6 +63,7 @@ || (auth.username.$error.required && user.submitted) }" autofocus required + autocomplete="off" >
This is a required field. @@ -83,6 +85,7 @@ && !auth.password.$pristine) || (auth.password.$error.required && user.submitted) }" required + autocomplete="new-password" >
This is a required field. diff --git a/setup/view/magento/setup/system-config.phtml b/setup/view/magento/setup/system-config.phtml index 65c13ab3cdf18..55087c5a99491 100644 --- a/setup/view/magento/setup/system-config.phtml +++ b/setup/view/magento/setup/system-config.phtml @@ -57,7 +57,7 @@

Magento Marketplace

Sign in to sync your Magento Marketplace purchases.

- +
@@ -74,6 +74,7 @@ || (auth.username.$error.required && user.submitted)}" autofocus required + autocomplete="off" >
This is a required field. @@ -100,7 +101,7 @@ ng-class="{ 'invalid' : (auth.password.$error.required && !auth.password.$pristine) || (auth.password.$error.required && user.submitted) }" required - autocomplete="off" + autocomplete="new-password" >
This is a required field.