From 3feda05339677a30590230745619db035781752d Mon Sep 17 00:00:00 2001 From: Mobecls Date: Fri, 8 Jun 2018 17:16:42 +0300 Subject: [PATCH 0001/1158] 14294 - Fixes 'back' functionality after switching a store view. --- .../Store/view/frontend/templates/switch/languages.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml b/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml index 80152dbb9a08f..6d041a9e22c5d 100644 --- a/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml +++ b/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml @@ -27,7 +27,7 @@ getStores() as $_lang): ?> getId() != $block->getCurrentStoreId()): ?>
  • - + escapeHtml($_lang->getName()) ?>
  • From fa2c3b5f5cb37f04c12e12b8bf1673ac0c13a5bb Mon Sep 17 00:00:00 2001 From: Artem Klimov Date: Sat, 30 Jun 2018 15:14:03 +0300 Subject: [PATCH 0002/1158] Alphabetize Schema Fields#11 --- lib/internal/Magento/Framework/GraphQl/Config.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index 8d40d7fa6bb49..e6dc128e4dd43 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -53,6 +53,11 @@ public function getConfigElement(string $configElementName) : ConfigElementInter sprintf('Config element "%s" is not declared in GraphQL schema', $configElementName) ); } + + if (!empty($data['fields']) && is_array($data['fields'])) { + ksort($data['fields']); + } + return $this->configElementFactory->createFromConfigData($data); } From 6a68bd880131a22bacdbf18b25f274c5c8cc236b Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Wed, 25 Jul 2018 13:08:12 +0200 Subject: [PATCH 0003/1158] Query complexity limiter introduced --- app/code/Magento/GraphQl/etc/di.xml | 6 +++ .../GraphQl/Query/QueryComplexityLimiter.php | 53 +++++++++++++++++++ .../GraphQl/Query/QueryProcessor.php | 23 ++++---- 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index 105fa8bf166b2..4aed25ac7bf4a 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -97,4 +97,10 @@ + + + 50 + 150 + + diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php new file mode 100644 index 0000000000000..be768d9f8defd --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -0,0 +1,53 @@ +queryDepth = $queryDepth; + $this->queryComplexity = $queryComplexity; + } + + public function execute(bool $disableIntrospection = false): void + { + DocumentValidator::addRule(new QueryDepth($this->queryDepth)); + DocumentValidator::addRule(new QueryComplexity($this->queryComplexity)); + + if ($disableIntrospection) { + DocumentValidator::addRule(new DisableIntrospection()); + } + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index 94a0e5a1c1a6e..0a23e4d00e8c7 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -7,9 +7,6 @@ namespace Magento\Framework\GraphQl\Query; -use GraphQL\Validator\DocumentValidator; -use GraphQL\Validator\Rules\DisableIntrospection; -use GraphQL\Validator\Rules\QueryDepth; use Magento\Framework\GraphQl\Exception\ExceptionFormatter; use Magento\Framework\GraphQl\Schema; use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; @@ -24,12 +21,21 @@ class QueryProcessor */ private $exceptionFormatter; + /** + * @var QueryComplexityLimiter + */ + protected $queryComplexityLimiter; + /** * @param ExceptionFormatter $exceptionFormatter + * @param QueryComplexityLimiter $queryComplexityChecker */ - public function __construct(ExceptionFormatter $exceptionFormatter) - { + public function __construct( + ExceptionFormatter $exceptionFormatter, + QueryComplexityLimiter $queryComplexityChecker + ) { $this->exceptionFormatter = $exceptionFormatter; + $this->queryComplexityLimiter = $queryComplexityChecker; } /** @@ -49,10 +55,9 @@ public function process( array $variableValues = null, string $operationName = null ) : array { - if (!$this->exceptionFormatter->shouldShowDetail()) { - DocumentValidator::addRule(new QueryDepth(10)); - DocumentValidator::addRule(new DisableIntrospection()); - } + $disableIntrospection = $this->exceptionFormatter->shouldShowDetail(); + $this->queryComplexityLimiter->execute($disableIntrospection); + $rootValue = null; return \GraphQL\GraphQL::executeQuery( $schema, From 660e393a1087060a838dc299ea80606ddb08df50 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Thu, 26 Jul 2018 11:11:01 +0200 Subject: [PATCH 0004/1158] Added some missing PHPDoc --- .../Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index be768d9f8defd..993390f5cfd22 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -41,6 +41,9 @@ public function __construct( $this->queryComplexity = $queryComplexity; } + /** + * @param bool $disableIntrospection + */ public function execute(bool $disableIntrospection = false): void { DocumentValidator::addRule(new QueryDepth($this->queryDepth)); From 351ae3784d0a148c40c89e581f9b6f0f61675a9a Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Thu, 26 Jul 2018 12:04:33 +0200 Subject: [PATCH 0005/1158] Added API-functional test for query limiter --- .../Framework/QueryComplexityLimiterTest.php | 332 ++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php new file mode 100644 index 0000000000000..fe278eaef1914 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -0,0 +1,332 @@ +graphQlQuery($query); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testQueryDepthIsLimited() + { + $query + = <<graphQlQuery($query); + } +} From 9aedd10c130d3455c352d3a3bddad856a75dd82d Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Thu, 26 Jul 2018 12:06:12 +0200 Subject: [PATCH 0006/1158] Constructor argument renamed --- .../Magento/Framework/GraphQl/Query/QueryProcessor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index 0a23e4d00e8c7..e1c9c6d6dbdfe 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -28,14 +28,14 @@ class QueryProcessor /** * @param ExceptionFormatter $exceptionFormatter - * @param QueryComplexityLimiter $queryComplexityChecker + * @param QueryComplexityLimiter $queryComplexityLimiter */ public function __construct( ExceptionFormatter $exceptionFormatter, - QueryComplexityLimiter $queryComplexityChecker + QueryComplexityLimiter $queryComplexityLimiter ) { $this->exceptionFormatter = $exceptionFormatter; - $this->queryComplexityLimiter = $queryComplexityChecker; + $this->queryComplexityLimiter = $queryComplexityLimiter; } /** From 88fb39883b20bad5500e8a7e1fd492ed33bfecf9 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Mon, 30 Jul 2018 14:34:55 +0200 Subject: [PATCH 0007/1158] Fixed introspection disabling expression --- lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index e1c9c6d6dbdfe..e3a2ea3fa753e 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -55,7 +55,7 @@ public function process( array $variableValues = null, string $operationName = null ) : array { - $disableIntrospection = $this->exceptionFormatter->shouldShowDetail(); + $disableIntrospection = !$this->exceptionFormatter->shouldShowDetail(); $this->queryComplexityLimiter->execute($disableIntrospection); $rootValue = null; From 99b1d1d5397cc3fb97551699647a33717a6ed3f6 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Mon, 30 Jul 2018 14:53:14 +0200 Subject: [PATCH 0008/1158] Reduced limiting values --- app/code/Magento/GraphQl/etc/di.xml | 4 +- .../Framework/QueryComplexityLimiterTest.php | 173 +----------------- .../GraphQl/Query/QueryComplexityLimiter.php | 4 +- 3 files changed, 7 insertions(+), 174 deletions(-) diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index 4aed25ac7bf4a..529280b7cbb6e 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -99,8 +99,8 @@ - 50 - 150 + 10 + 50 diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php index fe278eaef1914..c5f645a94472a 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -86,109 +86,6 @@ public function testQueryComplexityIsLimited() id types } - categories { - id - position - level - url_key - url_path - product_count - breadcrumbs { - category_id - category_name - category_url_key - } - products { - items { - name - special_from_date - special_to_date - new_to_date - new_from_date - tier_price - manufacturer - thumbnail - sku - image - canonical_url - updated_at - created_at - categories { - id - position - level - url_key - url_path - product_count - breadcrumbs { - category_id - category_name - category_url_key - } - products { - items { - name - special_from_date - special_to_date - new_to_date - new_from_date - tier_price - manufacturer - sku - image - canonical_url - updated_at - created_at - categories { - id - position - level - url_key - url_path - product_count - breadcrumbs { - category_id - category_name - category_url_key - } - products { - items { - name - special_from_date - special_to_date - new_to_date - new_from_date - tier_price - manufacturer - sku - image - thumbnail - canonical_url - updated_at - created_at - categories { - id - position - level - url_key - url_path - product_count - default_sort_by - breadcrumbs { - category_id - category_name - category_url_key - } - } - } - } - } - } - } - } - } - } - } } } } @@ -201,7 +98,7 @@ public function testQueryComplexityIsLimited() } QUERY; - self::expectExceptionMessageRegExp('/Max query complexity should be 150 but got 151/'); + self::expectExceptionMessageRegExp('/Max query complexity should be 50 but got 62/'); $this->graphQlQuery($query); } @@ -238,71 +135,7 @@ public function testQueryDepthIsLimited() categories { products { items { - categories { - products { - items { - categories { - products { - items { - categories { - products { - items { - name, - categories { - products { - items { - categories { - products { - items { - categories{ - products { - items { - categories { - products { - items { - categories { - products { - items { - categories { - products { - items { - name, - categories { - products { - items { - categories { - name - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } + name } } } @@ -326,7 +159,7 @@ public function testQueryDepthIsLimited() } } QUERY; - self::expectExceptionMessageRegExp('/Max query depth should be 50 but got 51/'); + self::expectExceptionMessageRegExp('/Max query depth should be 10 but got 20/'); $this->graphQlQuery($query); } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index 993390f5cfd22..d2d9477e67b1e 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -34,8 +34,8 @@ class QueryComplexityLimiter * @param int $queryComplexity */ public function __construct( - int $queryDepth = 50, - int $queryComplexity = 150 + int $queryDepth = 10, + int $queryComplexity = 50 ) { $this->queryDepth = $queryDepth; $this->queryComplexity = $queryComplexity; From e671008cb2a261842823d64dd4ea20040fafcc5f Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak Date: Tue, 14 Aug 2018 15:26:27 +0300 Subject: [PATCH 0009/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Template fixed: added checking of all gift options. Also added possibility to change order level options visibility from other modules. --- .../GiftMessage/Block/Message/Inline.php | 21 +++++++++++++++++-- .../view/frontend/templates/inline.phtml | 9 +++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/GiftMessage/Block/Message/Inline.php b/app/code/Magento/GiftMessage/Block/Message/Inline.php index e5b80848661fd..1a874cb5ea4ae 100644 --- a/app/code/Magento/GiftMessage/Block/Message/Inline.php +++ b/app/code/Magento/GiftMessage/Block/Message/Inline.php @@ -238,7 +238,7 @@ public function getMessage($entity = null) */ public function getItems() { - if (!$this->getData('items')) { + if (!$this->hasData('items')) { $items = []; $entityItems = $this->getEntity()->getAllItems(); @@ -325,6 +325,23 @@ public function getEscaped($value, $defaultValue = '') return $this->escapeHtml(trim($value) != '' ? $value : $defaultValue); } + /** + * Check availability of order level functionality + * + * @return bool + */ + public function isOrderLevelAvailable() + { + $entity = $this->getEntity(); + if (!$entity->hasIsGiftOptionsAvailable()) { + $this->_eventManager->dispatch('gift_options_prepare', ['entity' => $entity]); + if (!$entity->getIsGiftOptionsAvailable()) { + $entity->setIsGiftOptionsAvailable($this->isMessagesAvailable()); + } + } + return $entity->getIsGiftOptionsAvailable(); + } + /** * Check availability of giftmessages on order level * @@ -355,7 +372,7 @@ public function isItemMessagesAvailable($item) protected function _toHtml() { // render HTML when messages are allowed for order or for items only - if ($this->isItemsAvailable() || $this->isMessagesAvailable()) { + if ($this->isItemsAvailable() || $this->isOrderLevelAvailable()) { return parent::_toHtml(); } return ''; diff --git a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml index dec54cfeb9df9..8c58959be15b7 100644 --- a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml +++ b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml @@ -18,7 +18,7 @@
    - isMessagesAvailable()): ?> + isOrderLevelAvailable()): ?>
    getEntityHasMessage()): ?> checked="checked" class="checkbox" /> @@ -28,6 +28,7 @@
    + isMessagesAvailable()): ?>
    - + isItemsAvailable()): ?>
    @@ -152,6 +154,7 @@
    + isOrderLevelAvailable()): ?>
    getEntityHasMessage()): ?> checked="checked" class="checkbox" /> @@ -192,7 +195,7 @@
    - + isItemsAvailable()): ?>
    From d764998480c7853c13c88d26a4530083cbd8a0a8 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Thu, 16 Aug 2018 14:21:51 +0300 Subject: [PATCH 0010/1158] MAGETWO-92170: Redundant File Names for Quote Attachments --- lib/internal/Magento/Framework/File/Uploader.php | 10 ++++++---- nginx.conf.sample | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/internal/Magento/Framework/File/Uploader.php b/lib/internal/Magento/Framework/File/Uploader.php index 33f458d2082e1..2b768fb2dbdce 100644 --- a/lib/internal/Magento/Framework/File/Uploader.php +++ b/lib/internal/Magento/Framework/File/Uploader.php @@ -204,20 +204,22 @@ public function save($destinationFolder, $newFileName = null) $this->_result = false; $destinationFile = $destinationFolder; $fileName = isset($newFileName) ? $newFileName : $this->_file['name']; - $fileName = self::getCorrectFileName($fileName); + $fileName = static::getCorrectFileName($fileName); if ($this->_enableFilesDispersion) { $fileName = $this->correctFileNameCase($fileName); $this->setAllowCreateFolders(true); - $this->_dispretionPath = self::getDispersionPath($fileName); + $this->_dispretionPath = static::getDispersionPath($fileName); $destinationFile .= $this->_dispretionPath; $this->_createDestinationFolder($destinationFile); } if ($this->_allowRenameFiles) { - $fileName = self::getNewFileName(self::_addDirSeparator($destinationFile) . $fileName); + $fileName = static::getNewFileName( + static::_addDirSeparator($destinationFile) . $fileName + ); } - $destinationFile = self::_addDirSeparator($destinationFile) . $fileName; + $destinationFile = static::_addDirSeparator($destinationFile) . $fileName; try { $this->_result = $this->_moveFile($this->_file['tmp_name'], $destinationFile); diff --git a/nginx.conf.sample b/nginx.conf.sample index 6f87a9a076666..90604808f6ec0 100644 --- a/nginx.conf.sample +++ b/nginx.conf.sample @@ -161,7 +161,7 @@ location /media/import/ { } # PHP entry point for main application -location ~ (index|get|static|report|404|503|health_check)\.php$ { +location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check)\.php$ { try_files $uri =404; fastcgi_pass fastcgi_backend; fastcgi_buffers 1024 4k; From ddb642c10e70c1acab5683beaf8d7d5b4b5e8ffd Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak Date: Mon, 20 Aug 2018 11:05:50 +0300 Subject: [PATCH 0011/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Moved saving toolbar params to session from block to model. Save params before generating layout xml. --- .../Block/Product/ProductList/Toolbar.php | 43 ++++- .../Catalog/Controller/Category/View.php | 12 +- .../Product/ProductList/ToolbarMemorizer.php | 161 ++++++++++++++++++ 3 files changed, 208 insertions(+), 8 deletions(-) create mode 100644 app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 0b8d2d6c89e72..0e971dcb5b9f5 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -7,6 +7,7 @@ use Magento\Catalog\Helper\Product\ProductList; use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel; +use Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer; /** * Product list toolbar @@ -77,6 +78,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template /** * @var bool $_paramsMemorizeAllowed + * @deprecated */ protected $_paramsMemorizeAllowed = true; @@ -96,6 +98,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template * Catalog session * * @var \Magento\Catalog\Model\Session + * @deprecated */ protected $_catalogSession; @@ -104,6 +107,11 @@ class Toolbar extends \Magento\Framework\View\Element\Template */ protected $_toolbarModel; + /** + * @var ToolbarMemorizer + */ + private $toolbarMemorizer; + /** * @var ProductList */ @@ -119,6 +127,11 @@ class Toolbar extends \Magento\Framework\View\Element\Template */ protected $_postDataHelper; + /** + * @var \Magento\Framework\App\Http\Context + */ + private $httpContext; + /** * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Catalog\Model\Session $catalogSession @@ -127,6 +140,8 @@ class Toolbar extends \Magento\Framework\View\Element\Template * @param \Magento\Framework\Url\EncoderInterface $urlEncoder * @param ProductList $productListHelper * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper + * @param ToolbarMemorizer|null $toolbarMemorizer + * @param \Magento\Framework\App\Http\Context|null $httpContext * @param array $data */ public function __construct( @@ -137,6 +152,8 @@ public function __construct( \Magento\Framework\Url\EncoderInterface $urlEncoder, ProductList $productListHelper, \Magento\Framework\Data\Helper\PostHelper $postDataHelper, + ToolbarMemorizer $toolbarMemorizer = null, + \Magento\Framework\App\Http\Context $httpContext = null, array $data = [] ) { $this->_catalogSession = $catalogSession; @@ -145,6 +162,12 @@ public function __construct( $this->urlEncoder = $urlEncoder; $this->_productListHelper = $productListHelper; $this->_postDataHelper = $postDataHelper; + $this->toolbarMemorizer = $toolbarMemorizer ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + ToolbarMemorizer::class + ); + $this->httpContext = $httpContext ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Http\Context::class + ); parent::__construct($context, $data); } @@ -152,6 +175,7 @@ public function __construct( * Disable list state params memorizing * * @return $this + * @deprecated */ public function disableParamsMemorizing() { @@ -165,6 +189,7 @@ public function disableParamsMemorizing() * @param string $param parameter name * @param mixed $value parameter value * @return $this + * @deprecated */ protected function _memorizeParam($param, $value) { @@ -244,13 +269,13 @@ public function getCurrentOrder() $defaultOrder = $keys[0]; } - $order = $this->_toolbarModel->getOrder(); + $order = $this->toolbarMemorizer->getOrder(); if (!$order || !isset($orders[$order])) { $order = $defaultOrder; } if ($order != $defaultOrder) { - $this->_memorizeParam('sort_order', $order); + $this->httpContext->setValue(ToolbarModel::ORDER_PARAM_NAME, $order, $defaultOrder); } $this->setData('_current_grid_order', $order); @@ -270,13 +295,13 @@ public function getCurrentDirection() } $directions = ['asc', 'desc']; - $dir = strtolower($this->_toolbarModel->getDirection()); + $dir = strtolower($this->toolbarMemorizer->getDirection()); if (!$dir || !in_array($dir, $directions)) { $dir = $this->_direction; } if ($dir != $this->_direction) { - $this->_memorizeParam('sort_direction', $dir); + $this->httpContext->setValue(ToolbarModel::DIRECTION_PARAM_NAME, $dir, $this->_direction); } $this->setData('_current_grid_direction', $dir); @@ -412,11 +437,15 @@ public function getCurrentMode() return $mode; } $defaultMode = $this->_productListHelper->getDefaultViewMode($this->getModes()); - $mode = $this->_toolbarModel->getMode(); + $mode = $this->toolbarMemorizer->getMode(); if (!$mode || !isset($this->_availableMode[$mode])) { $mode = $defaultMode; } + if ($mode != $defaultMode) { + $this->httpContext->setValue(ToolbarModel::MODE_PARAM_NAME, $mode, $defaultMode); + } + $this->setData('_current_grid_mode', $mode); return $mode; } @@ -568,13 +597,13 @@ public function getLimit() $defaultLimit = $keys[0]; } - $limit = $this->_toolbarModel->getLimit(); + $limit = $this->toolbarMemorizer->getLimit(); if (!$limit || !isset($limits[$limit])) { $limit = $defaultLimit; } if ($limit != $defaultLimit) { - $this->_memorizeParam('limit_page', $limit); + $this->httpContext->setValue(ToolbarModel::LIMIT_PARAM_NAME, $limit, $defaultLimit); } $this->setData('_current_limit', $limit); diff --git a/app/code/Magento/Catalog/Controller/Category/View.php b/app/code/Magento/Catalog/Controller/Category/View.php index 226e572505076..d451357a7c129 100644 --- a/app/code/Magento/Catalog/Controller/Category/View.php +++ b/app/code/Magento/Catalog/Controller/Category/View.php @@ -8,6 +8,7 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Model\Layer\Resolver; +use Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\View\Result\PageFactory; @@ -69,6 +70,11 @@ class View extends \Magento\Framework\App\Action\Action */ protected $categoryRepository; + /** + * @var ToolbarMemorizer + */ + private $toolbarMemorizer; + /** * Constructor * @@ -82,6 +88,7 @@ class View extends \Magento\Framework\App\Action\Action * @param \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory * @param Resolver $layerResolver * @param CategoryRepositoryInterface $categoryRepository + * @param ToolbarMemorizer|null $toolbarMemorizer * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -94,7 +101,8 @@ public function __construct( PageFactory $resultPageFactory, \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory, Resolver $layerResolver, - CategoryRepositoryInterface $categoryRepository + CategoryRepositoryInterface $categoryRepository, + ToolbarMemorizer $toolbarMemorizer = null ) { parent::__construct($context); $this->_storeManager = $storeManager; @@ -106,6 +114,7 @@ public function __construct( $this->resultForwardFactory = $resultForwardFactory; $this->layerResolver = $layerResolver; $this->categoryRepository = $categoryRepository; + $this->toolbarMemorizer = $toolbarMemorizer ?: $context->getObjectManager()->get(ToolbarMemorizer::class); } /** @@ -130,6 +139,7 @@ protected function _initCategory() } $this->_catalogSession->setLastVisitedCategoryId($category->getId()); $this->_coreRegistry->register('current_category', $category); + $this->toolbarMemorizer->memorizeParams(); try { $this->_eventManager->dispatch( 'catalog_controller_category_init_after', diff --git a/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php b/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php new file mode 100644 index 0000000000000..1ff63a0fa3448 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php @@ -0,0 +1,161 @@ +toolbarModel = $toolbarModel; + $this->catalogSession = $catalogSession; + } + + /** + * Get sort order + * + * @return string|bool + */ + public function getOrder() + { + if ($this->order === null) { + $this->order = $this->toolbarModel->getOrder() ?? + $this->catalogSession->getData(Toolbar::ORDER_PARAM_NAME); + } + return $this->order; + } + + /** + * Get sort direction + * + * @return string|bool + */ + public function getDirection() + { + if ($this->direction === null) { + $this->direction = $this->toolbarModel->getDirection() ?? + $this->catalogSession->getData(Toolbar::DIRECTION_PARAM_NAME); + } + return $this->direction; + } + + /** + * Get sort mode + * + * @return string|bool + */ + public function getMode() + { + if ($this->mode === null) { + $this->mode = $this->toolbarModel->getMode() ?? + $this->catalogSession->getData(Toolbar::MODE_PARAM_NAME); + } + return $this->mode; + } + + /** + * Get products per page limit + * + * @return string|bool + */ + public function getLimit() + { + if ($this->limit === null) { + $this->limit = $this->toolbarModel->getLimit() ?? + $this->catalogSession->getData(Toolbar::LIMIT_PARAM_NAME); + } + return $this->limit; + } + + /** + * Disable list state params memorizing + * + * @return $this + */ + public function disableParamsMemorizing() + { + $this->paramsMemorizeAllowed = false; + return $this; + } + + /** + * Method to save all catalog parameters in catalog session + * + * @return void + */ + public function memorizeParams() + { + $this->memorizeParam(Toolbar::ORDER_PARAM_NAME, $this->getOrder()) + ->memorizeParam(Toolbar::DIRECTION_PARAM_NAME, $this->getDirection()) + ->memorizeParam(Toolbar::MODE_PARAM_NAME, $this->getMode()) + ->memorizeParam(Toolbar::LIMIT_PARAM_NAME, $this->getLimit()); + } + + /** + * Memorize parameter value for session + * + * @param string $param parameter name + * @param mixed $value parameter value + * @return $this + */ + private function memorizeParam($param, $value) + { + if ($value && $this->paramsMemorizeAllowed && + !$this->catalogSession->getParamsMemorizeDisabled() && + $this->catalogSession->getData($param) != $value + ) { + $this->catalogSession->setData($param, $value); + } + return $this; + } +} From 90b1c761e87f958cde0fda4710086234547d354e Mon Sep 17 00:00:00 2001 From: Saravanan Date: Mon, 27 Aug 2018 10:40:01 +0530 Subject: [PATCH 0012/1158] 17754-Fixed validation while creating new product attributes in admin --- .../Catalog/Controller/Adminhtml/Product/Attribute/Save.php | 4 ++-- lib/web/mage/validation.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 817de6828e48d..0b3b8b06c969f 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -167,12 +167,12 @@ public function execute() $attributeCode = $attributeCode ?: $this->generateCode($this->getRequest()->getParam('frontend_label')[0]); if (strlen($attributeCode) > 0) { $validatorAttrCode = new \Zend_Validate_Regex( - ['pattern' => '/^[a-z\x{600}-\x{6FF}][a-z\x{600}-\x{6FF}_0-9]{0,30}$/u'] + ['pattern' => '/^[a-zA-Z\x{600}-\x{6FF}][a-zA-Z\x{600}-\x{6FF}_0-9]{0,30}$/u'] ); if (!$validatorAttrCode->isValid($attributeCode)) { $this->messageManager->addErrorMessage( __( - 'Attribute code "%1" is invalid. Please use only letters (a-z), ' . + 'Attribute code "%1" is invalid. Please use only letters (a-z or A-Z), ' . 'numbers (0-9) or underscore(_) in this field, first character should be a letter.', $attributeCode ) diff --git a/lib/web/mage/validation.js b/lib/web/mage/validation.js index d08819ebe94aa..d0e77b802f77a 100644 --- a/lib/web/mage/validation.js +++ b/lib/web/mage/validation.js @@ -980,9 +980,9 @@ ], 'validate-code': [ function (v) { - return $.mage.isEmptyNoTrim(v) || /^[a-z]+[a-z0-9_]+$/.test(v); + return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z]+[a-zA-Z0-9_]+$/.test(v); }, - $.mage.__('Please use only letters (a-z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.') //eslint-disable-line max-len + $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.') //eslint-disable-line max-len ], 'validate-alphanum': [ function (v) { From 22c185efdf7c72f5967f0537b00af17df9d753d6 Mon Sep 17 00:00:00 2001 From: Saravanan Date: Mon, 27 Aug 2018 13:57:20 +0530 Subject: [PATCH 0013/1158] Updated the unit test controller to save the attribute --- .../Catalog/Controller/Adminhtml/Product/AttributeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php index 4261873cc8e6e..3d0c0a96988f5 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php @@ -147,7 +147,7 @@ public function testWrongAttributeCode() /** @var \Magento\Framework\Message\Error $message */ $message = $messages->getItemsByType('error')[0]; $this->assertEquals( - 'Attribute code "_()&&&?" is invalid. Please use only letters (a-z),' + 'Attribute code "_()&&&?" is invalid. Please use only letters (a-z or A-Z),' . ' numbers (0-9) or underscore(_) in this field, first character should be a letter.', $message->getText() ); From 9ef1afe6ae278615c23c0deb73b9fdd5f16b1b07 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak Date: Tue, 28 Aug 2018 17:56:51 +0300 Subject: [PATCH 0014/1158] MAGETWO-91563: Gift wrapping selection does not display in shopping cart - Used right model to observe gift wrapping options. --- .../GiftMessage/view/frontend/web/js/view/gift-message.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js b/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js index d025f6974f35e..4c455c83a77a9 100644 --- a/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js +++ b/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js @@ -31,8 +31,9 @@ define([ this.itemId = this.itemId || 'orderLevel'; model = new GiftMessage(this.itemId); - giftOptions.addOption(model); this.model = model; + this.isResultBlockVisible(); + giftOptions.addOption(model); this.model.getObservable('isClear').subscribe(function (value) { if (value == true) { //eslint-disable-line eqeqeq @@ -40,8 +41,6 @@ define([ self.model.getObservable('alreadyAdded')(true); } }); - - this.isResultBlockVisible(); }, /** From f2e053a7d6e87252ae526049b2253566d19ee0a7 Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan Date: Tue, 28 Aug 2018 19:23:23 +0400 Subject: [PATCH 0015/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Add automated test --- .../Section/StoreFrontShoppingCartSection.xml | 15 +++++ .../CleanConfigsForGiftOptionsActionGroup.xml | 32 +++++++++++ ...ftWrappingForOrderItemsOnlyActionGroup.xml | 32 +++++++++++ .../Mftf/Section/AdminSalesConfigSection.xml | 16 +++++- .../CheckingGiftOptionsActionGroup.xml | 23 ++++++++ .../Section/GiftOptionsOnFrontSection.xml | 13 +++++ .../StoreFrontCheckingGiftOptionsTest.xml | 57 +++++++++++++++++++ 7 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml create mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml create mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml create mode 100644 app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml create mode 100644 app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml create mode 100644 app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml new file mode 100644 index 0000000000000..303c5e526423f --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml @@ -0,0 +1,15 @@ + + + + +
    + + +
    +
    diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml new file mode 100644 index 0000000000000..72d88b13736cc --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml new file mode 100644 index 0000000000000..8f5b491575e95 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml index 4897e8415c1b8..aefb7c5441c5b 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml @@ -5,9 +5,23 @@ * See COPYING.txt for license details. */ --> - +
    + + + + + + + + + + + + + +
    \ No newline at end of file diff --git a/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml b/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml new file mode 100644 index 0000000000000..05dad757e287f --- /dev/null +++ b/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml b/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml new file mode 100644 index 0000000000000..9856f009197c1 --- /dev/null +++ b/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml @@ -0,0 +1,13 @@ + + + +
    + + +
    +
    \ No newline at end of file diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml b/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml new file mode 100644 index 0000000000000..7b4bd56ae74e8 --- /dev/null +++ b/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + <description value="Admin should be able to control gift options"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-94209"/> + <group value="Gift"/> + </annotations> + <before> + <createData stepKey="category" entity="SimpleSubCategory"/> + <createData stepKey="product1" entity="SimpleProduct"> + <requiredEntity createDataKey="category"/> + </createData> + <createData stepKey="product2" entity="SimpleProduct"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="Simple_US_Customer" stepKey="customer"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup" stepKey="configureGiftOptions"/> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> + <argument name="Customer" value="$$customer$$"/> + </actionGroup> + </before> + + <amOnPage url="$$product1.name$$.html" stepKey="goToProduct1"/> + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProduct1"> + <argument name="productName" value="$$product1.name$$"/> + </actionGroup> + <amOnPage url="$$product2.name$$.html" stepKey="goToProduct2"/> + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProduct2"> + <argument name="productName" value="$$product2.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="openCart"/> + <actionGroup ref="CheckingGiftOptionsActionGroup" stepKey="checkGiftOptions"/> + + <after> + <actionGroup ref="CleanConfigsForGiftOptionsActionGroup" stepKey="cleanGiftOptionsConfigs"/> + <deleteData stepKey="deleteCategory" createDataKey="category"/> + <deleteData stepKey="deleteProduct1" createDataKey="product1"/> + <deleteData stepKey="deleteProduct2" createDataKey="product2"/> + <deleteData stepKey="deleteCustomer" createDataKey="customer"/> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + </after> + </test> +</tests> From 41f81e050ccd25ae379d35fa37cd5e65d6a92b0d Mon Sep 17 00:00:00 2001 From: Roman Leshchenko <rleshchenko@magento.com> Date: Thu, 30 Aug 2018 14:33:50 +0300 Subject: [PATCH 0016/1158] MAGETWO-90725: Wrong session messages behavior --- .../Model/System/Config/Backend/Ttl.php | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/PageCache/Model/System/Config/Backend/Ttl.php b/app/code/Magento/PageCache/Model/System/Config/Backend/Ttl.php index dab8d7be16dd7..d9d26d0848c24 100644 --- a/app/code/Magento/PageCache/Model/System/Config/Backend/Ttl.php +++ b/app/code/Magento/PageCache/Model/System/Config/Backend/Ttl.php @@ -6,6 +6,10 @@ namespace Magento\PageCache\Model\System\Config\Backend; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Escaper; +use Magento\Framework\App\Config\ScopeConfigInterface; + /** * Backend model for processing Public content cache lifetime settings * @@ -13,6 +17,36 @@ */ class Ttl extends \Magento\Framework\App\Config\Value { + /** + * @var Escaper + */ + private $escaper; + + /** + * Ttl constructor. + * @param \Magento\Framework\Model\Context $context + * @param \Magento\Framework\Registry $registry + * @param ScopeConfigInterface $config + * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList + * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource + * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection + * @param array $data + * @param Escaper|null $escaper + */ + public function __construct( + \Magento\Framework\Model\Context $context, + \Magento\Framework\Registry $registry, + ScopeConfigInterface $config, + \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList, + ?\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, + ?\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, + array $data = [], + ?Escaper $escaper = null + ) { + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + $this->escaper = $escaper ?: ObjectManager::getInstance()->create(Escaper::class); + } + /** * Throw exception if Ttl data is invalid or empty * @@ -24,7 +58,10 @@ public function beforeSave() $value = $this->getValue(); if ($value < 0 || !preg_match('/^[0-9]+$/', $value)) { throw new \Magento\Framework\Exception\LocalizedException( - __('Ttl value "%1" is not valid. Please use only numbers equal or greater than zero.', $value) + __( + 'Ttl value "%1" is not valid. Please use only numbers equal or greater than zero.', + $this->escaper->escapeHtml($value) + ) ); } return $this; From ea9168570ae0f2d5bcf1911b13b46b760a9cb0eb Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Fri, 31 Aug 2018 14:42:59 +0300 Subject: [PATCH 0017/1158] MAGETWO-91628: Bundle product price doubled when switching currency - Fixed an issue with quote item options relates to a bundled products. --- .../Magento/Bundle/Model/Product/Type.php | 2 +- .../Plugin/UpdatePriceInQuoteItemOptions.php | 55 +++++++++++++++++++ app/code/Magento/Bundle/etc/di.xml | 3 + 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Bundle/Plugin/UpdatePriceInQuoteItemOptions.php diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index 17ecba545efad..c5f3aa0a84995 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -735,7 +735,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p $price = $product->getPriceModel() ->getSelectionFinalTotalPrice($product, $selection, 0, $qty); $attributes = [ - 'price' => $this->priceCurrency->convert($price), + 'price' => $price, 'qty' => $qty, 'option_label' => $selection->getOption() ->getTitle(), diff --git a/app/code/Magento/Bundle/Plugin/UpdatePriceInQuoteItemOptions.php b/app/code/Magento/Bundle/Plugin/UpdatePriceInQuoteItemOptions.php new file mode 100644 index 0000000000000..d5aafb8ad2b61 --- /dev/null +++ b/app/code/Magento/Bundle/Plugin/UpdatePriceInQuoteItemOptions.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Bundle\Plugin; + +use Magento\Quote\Model\Quote\Item as OrigQuoteItem; +use Magento\Quote\Model\Quote\Item\AbstractItem; +use Magento\Framework\Serialize\SerializerInterface; + +/** + * Update prices stored in quote item options after calculating quote item's totals + */ +class UpdatePriceInQuoteItemOptions +{ + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @param SerializerInterface $serializer + */ + public function __construct(SerializerInterface $serializer) + { + $this->serializer = $serializer; + } + + /** + * Update price on quote item options level + * + * @param OrigQuoteItem $subject + * @param AbstractItem $result + * @return AbstractItem + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterCalcRowTotal(OrigQuoteItem $subject, AbstractItem $result) + { + $bundleAttributes = $result->getProduct()->getCustomOption('bundle_selection_attributes'); + if ($bundleAttributes !== null) { + $actualPrice = $result->getPrice(); + $parsedValue = $this->serializer->unserialize($bundleAttributes->getValue()); + if (is_array($parsedValue) && array_key_exists('price', $parsedValue)) { + $parsedValue['price'] = $actualPrice; + } + $bundleAttributes->setValue($this->serializer->serialize($parsedValue)); + } + + return $result; + } +} diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index 733b089dccd4b..6f0cc04790cc2 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -123,6 +123,9 @@ </argument> </arguments> </type> + <type name="Magento\Quote\Model\Quote\Item"> + <plugin name="update_price_for_bundle_in_quote_item_option" type="Magento\Bundle\Plugin\UpdatePriceInQuoteItemOptions"/> + </type> <type name="Magento\Quote\Model\Quote\Item\ToOrderItem"> <plugin name="append_bundle_data_to_order" type="Magento\Bundle\Model\Plugin\QuoteItem"/> </type> From 1ff16642855a313b3b8e4a7a9a6e836c09769c69 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Mon, 3 Sep 2018 18:33:15 +0300 Subject: [PATCH 0018/1158] MAGETWO-94424: [2.3] Wrong product and shipping prices are applying on admin orders --- app/code/Magento/Store/Model/Store.php | 20 ++-- .../Store/Test/Unit/Model/StoreTest.php | 98 ++++++++++++++++++- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index af25957257421..32c9a78448428 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -902,23 +902,17 @@ public function setCurrentCurrencyCode($code) */ public function getCurrentCurrencyCode() { + $availableCurrencyCodes = \array_values($this->getAvailableCurrencyCodes(true)); // try to get currently set code among allowed - $code = $this->_httpContext->getValue(Context::CONTEXT_CURRENCY); - $code = $code === null ? $this->_getSession()->getCurrencyCode() : $code; - if (empty($code)) { + $code = $this->_httpContext->getValue(Context::CONTEXT_CURRENCY) ?? $this->_getSession()->getCurrencyCode(); + if (empty($code) || !\in_array($code, $availableCurrencyCodes)) { $code = $this->getDefaultCurrencyCode(); - } - if (in_array($code, $this->getAvailableCurrencyCodes(true))) { - return $code; + if (!\in_array($code, $availableCurrencyCodes) && !empty($availableCurrencyCodes)) { + $code = $availableCurrencyCodes[0]; + } } - // take first one of allowed codes - $codes = array_values($this->getAvailableCurrencyCodes(true)); - if (empty($codes)) { - // return default code, if no codes specified at all - return $this->getDefaultCurrencyCode(); - } - return array_shift($codes); + return $code; } /** diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php index f98cf5d892e07..f4a5010e51b88 100644 --- a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php @@ -3,11 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Store\Test\Unit\Model; use Magento\Framework\App\Config\ReinitableConfigInterface; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Session\SessionManagerInterface; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\Store; @@ -38,6 +38,16 @@ class StoreTest extends \PHPUnit\Framework\TestCase */ protected $filesystemMock; + /** + * @var ReinitableConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + /** + * @var SessionManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $sessionMock; + /** * @var \Magento\Framework\Url\ModifierInterface|\PHPUnit_Framework_MockObject_MockObject */ @@ -61,12 +71,22 @@ protected function setUp() 'isSecure', 'getServer', ]); + $this->filesystemMock = $this->getMockBuilder(\Magento\Framework\Filesystem::class) ->disableOriginalConstructor() ->getMock(); + $this->configMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->getMock(); + $this->sessionMock = $this->getMockBuilder(SessionManagerInterface::class) + ->setMethods(['getCurrencyCode']) + ->getMockForAbstractClass(); $this->store = $this->objectManagerHelper->getObject( \Magento\Store\Model\Store::class, - ['filesystem' => $this->filesystemMock] + [ + 'filesystem' => $this->filesystemMock, + 'config' => $this->configMock, + 'session' => $this->sessionMock, + ] ); $this->urlModifierMock = $this->createMock(\Magento\Framework\Url\ModifierInterface::class); @@ -694,6 +714,80 @@ public function testGetScopeTypeName() $this->assertEquals('Store View', $this->store->getScopeTypeName()); } + /** + * @param array $availableCodes + * @param string $currencyCode + * @param string $defaultCode + * @param string $expectedCode + * @return void + * @dataProvider currencyCodeDataProvider + */ + public function testGetCurrentCurrencyCode( + array $availableCodes, + string $currencyCode, + string $defaultCode, + string $expectedCode + ): void { + $this->store->setData('available_currency_codes', $availableCodes); + $this->sessionMock->method('getCurrencyCode') + ->willReturn($currencyCode); + $this->configMock->method('getValue') + ->with(\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_DEFAULT) + ->willReturn($defaultCode); + + $code = $this->store->getCurrentCurrencyCode(); + $this->assertEquals($expectedCode, $code); + } + + /** + * @return array + */ + public function currencyCodeDataProvider(): array + { + return [ + [ + [ + 'USD', + ], + 'USD', + 'USD', + 'USD', + ], + [ + [ + 'USD', + 'EUR', + ], + 'EUR', + 'USD', + 'EUR', + ], + [ + [ + 'EUR', + 'USD', + ], + 'GBP', + 'USD', + 'USD', + ], + [ + [ + 'USD', + ], + 'GBP', + 'EUR', + 'USD', + ], + [ + [], + 'GBP', + 'EUR', + 'EUR', + ], + ]; + } + /** * @param \Magento\Store\Model\Store $model */ From 38d5547049a0f2f6bf83b016b1af55961ccd753c Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Tue, 4 Sep 2018 13:47:33 +0400 Subject: [PATCH 0019/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Updated automated test --- .../CleanConfigsForGiftOptionsActionGroup.xml | 32 --------------- ...ftWrappingForOrderItemsOnlyActionGroup.xml | 32 --------------- .../Test/Mftf/Data/GiftOptionsData.xml | 40 +++++++++++++++++++ .../Test/Mftf/Metadata/gift_options-meta.xml | 31 ++++++++++++++ .../StoreFrontCheckingGiftOptionsTest.xml | 6 ++- 5 files changed, 75 insertions(+), 66 deletions(-) delete mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml delete mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml create mode 100644 app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml create mode 100644 app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml deleted file mode 100644 index 72d88b13736cc..0000000000000 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/CleanConfigsForGiftOptionsActionGroup.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="CleanConfigsForGiftOptionsActionGroup"> - <amOnPage url="{{AdminSalesConfigPage.url('')}}" stepKey="amOnSalesConfigPage"/> - <waitForPageLoad stepKey="waitForConfigPage" time="5"/> - <conditionalClick selector="{{AdminSalesConfigSection.giftOptions}}" - dependentSelector="{{AdminSalesConfigSection.allowGiftWrappingForOrderItems}}" visible="false" - stepKey="openGiftOptionsIfItIsClosed"/> - <waitForPageLoad stepKey="waitForGiftOptions" time="2"/> - <click stepKey="openOrderLevel" selector="{{AdminSalesConfigSection.allowGiftWrappingOnOrderLevel}}"/> - <click stepKey="chooseYesForOrderLevel" selector="{{AdminSalesConfigSection.levelYes}}"/> - <click stepKey="openOrderItems" selector="{{AdminSalesConfigSection.allowGiftWrappingForOrderItems}}"/> - <click stepKey="chooseYesForOrderItems" selector="{{AdminSalesConfigSection.itemsYes}}"/> - <click stepKey="openGiftReceipt" selector="{{AdminSalesConfigSection.allowGiftReceipt}}"/> - <click stepKey="chooseYesForReceipt" selector="{{AdminSalesConfigSection.receiptYes}}"/> - <click stepKey="openPrintedCard" selector="{{AdminSalesConfigSection.allowPrintedCard}}"/> - <click stepKey="chooseYesPrintedCard" selector="{{AdminSalesConfigSection.printedCardYes}}"/> - <click stepKey="closeGiftOptions" selector="{{AdminSalesConfigSection.giftOptions}}"/> - <click stepKey="save" selector="{{AdminConfigSection.saveButton}}"/> - <waitForPageLoad stepKey="waitForSevConfigs" time="5"/> - <see stepKey="seeSuccessMessage" userInput="You saved the configuration."/> - </actionGroup> -</actionGroups> - diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml deleted file mode 100644 index 8f5b491575e95..0000000000000 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup"> - <amOnPage url="{{AdminSalesConfigPage.url('')}}" stepKey="amOnSalesConfigPage"/> - <waitForPageLoad stepKey="waitForConfigPage" time="5"/> - <scrollTo stepKey="scrollToGiftOptions" selector="{{AdminSalesConfigSection.giftOptions}}"/> - <conditionalClick selector="{{AdminSalesConfigSection.giftOptions}}" - dependentSelector="{{AdminSalesConfigSection.allowGiftWrappingForOrderItems}}" visible="false" - stepKey="openGiftOptionsIfItIsClosed"/> - <waitForPageLoad stepKey="waitForGiftOptions" time="2"/> - <click stepKey="openOrderLevel" selector="{{AdminSalesConfigSection.allowGiftWrappingOnOrderLevel}}"/> - <click stepKey="chooseNoForOrderLevel" selector="{{AdminSalesConfigSection.levelNo}}"/> - <click stepKey="openOrderItems" selector="{{AdminSalesConfigSection.allowGiftWrappingForOrderItems}}"/> - <click stepKey="chooseYesForOrderItems" selector="{{AdminSalesConfigSection.itemsYes}}"/> - <click stepKey="openGiftReceipt" selector="{{AdminSalesConfigSection.allowGiftReceipt}}"/> - <click stepKey="chooseNoForReceipt" selector="{{AdminSalesConfigSection.receiptNo}}"/> - <click stepKey="openPrintedCard" selector="{{AdminSalesConfigSection.allowPrintedCard}}"/> - <click stepKey="chooseNoPrintedCard" selector="{{AdminSalesConfigSection.printedCardNo}}"/> - <click stepKey="save" selector="{{AdminConfigSection.saveButton}}"/> - <waitForPageLoad stepKey="waitForSevConfigs" time="5"/> - <see stepKey="seeSuccessMessage" userInput="You saved the configuration."/> - </actionGroup> -</actionGroups> - diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml b/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml new file mode 100644 index 0000000000000..b2bc71b5b7a7b --- /dev/null +++ b/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="ConfigAllowGiftWrappingForOrderItemsOnly" type="gift_options_config_state"> + <requiredEntity type="wrapping_allow_order">wrappingAllowOrder</requiredEntity> + <requiredEntity type="allow_gift_receipt">allowGiftReceipt</requiredEntity> + <requiredEntity type="allow_printed_card">allowPrintedCard</requiredEntity> + </entity> + <entity name="wrappingAllowOrder" type="wrapping_allow_order"> + <data key="value">0</data> + </entity> + <entity name="allowGiftReceipt" type="allow_gift_receipt"> + <data key="value">0</data> + </entity> + <entity name="allowPrintedCard" type="allow_printed_card"> + <data key="value">0</data> + </entity> + + <entity name="DefaultConfigGiftOptions" type="gift_options_config_state"> + <requiredEntity type="wrapping_allow_order">defaultWrappingAllowOrder</requiredEntity> + <requiredEntity type="allow_gift_receipt">defaultAllowGiftReceipt</requiredEntity> + <requiredEntity type="allow_printed_card">defaultAllowPrintedCard</requiredEntity> + </entity> + <entity name="defaultWrappingAllowOrder" type="wrapping_allow_order"> + <data key="value">1</data> + </entity> + <entity name="defaultAllowGiftReceipt" type="allow_gift_receipt"> + <data key="value">1</data> + </entity> + <entity name="defaultAllowPrintedCard" type="allow_printed_card"> + <data key="value">1</data> + </entity> +</entities> diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml b/app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml new file mode 100644 index 0000000000000..a32f5694f2470 --- /dev/null +++ b/app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="SalesGiftOptionsConfigState" dataType="gift_options_config_state" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST"> + <object key="groups" dataType="gift_options_config_state"> + <object key="gift_options" dataType="gift_options_config_state"> + <object key="fields" dataType="gift_options_config_state"> + <object key="wrapping_allow_order" dataType="wrapping_allow_order"> + <field key="value">string</field> + </object> + <object key="wrapping_allow_items" dataType="wrapping_allow_items"> + <field key="value">string</field> + </object> + <object key="allow_gift_receipt" dataType="allow_gift_receipt"> + <field key="value">string</field> + </object> + <object key="allow_printed_card" dataType="allow_printed_card"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml b/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml index 7b4bd56ae74e8..0bb5bf0e71fa8 100644 --- a/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml +++ b/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml @@ -27,11 +27,13 @@ <requiredEntity createDataKey="category"/> </createData> <createData entity="Simple_US_Customer" stepKey="customer"/> + <createData entity="ConfigAllowGiftWrappingForOrderItemsOnly" stepKey="configAllowGiftWrappingForOrderItemsOnly"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> - <actionGroup ref="ConfigAllowGiftWrappingForOrderItemsOnlyActionGroup" stepKey="configureGiftOptions"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> <argument name="Customer" value="$$customer$$"/> </actionGroup> + </before> <amOnPage url="$$product1.name$$.html" stepKey="goToProduct1"/> @@ -46,7 +48,7 @@ <actionGroup ref="CheckingGiftOptionsActionGroup" stepKey="checkGiftOptions"/> <after> - <actionGroup ref="CleanConfigsForGiftOptionsActionGroup" stepKey="cleanGiftOptionsConfigs"/> + <createData entity="DefaultConfigGiftOptions" stepKey="restoreDefaultConfigGiftOptions"/> <deleteData stepKey="deleteCategory" createDataKey="category"/> <deleteData stepKey="deleteProduct1" createDataKey="product1"/> <deleteData stepKey="deleteProduct2" createDataKey="product2"/> From 2a7cd23d460e8ff278730cafbf3a2a1f33ae2461 Mon Sep 17 00:00:00 2001 From: Oleksandr_Hodzevych <Oleksandr_Hodzevych@epam.com> Date: Mon, 3 Sep 2018 18:47:32 +0300 Subject: [PATCH 0020/1158] MAGETWO-91609: Problems with operator more/less in the "catalog Products List" widget - Fixed widget operator less or more --- .../Rule/Model/Condition/Sql/Builder.php | 4 + .../Unit/Model/Condition/Sql/BuilderTest.php | 119 ++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index 2894de0f19b87..1afe995f837ea 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -32,9 +32,13 @@ class Builder '==' => ':field = ?', '!=' => ':field <> ?', '>=' => ':field >= ?', + '>e;' => ':field >= ?', '>' => ':field > ?', + '>' => ':field > ?', '<=' => ':field <= ?', + '<e;' => ':field <= ?', '<' => ':field < ?', + '<' => ':field < ?', '{}' => ':field IN (?)', '!{}' => ':field NOT IN (?)', '()' => ':field IN (?)', diff --git a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php index daf7b1462c722..b3ddaa51c2605 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php @@ -78,4 +78,123 @@ public function testAttachConditionToCollection() $this->_builder->attachConditionToCollection($collection, $combine); } + + /** + * Test for attach condition to collection with operator in html format + * + * @covers \Magento\Rule\Model\Condition\Sql\Builder::attachConditionToCollection() + * @return void; + */ + public function testAttachConditionAsHtmlToCollection() + { + $abstractCondition = $this->getMockForAbstractClass( + \Magento\Rule\Model\Condition\AbstractCondition::class, + [], + '', + false, + false, + true, + ['getOperatorForValidate', 'getMappedSqlField', 'getAttribute', 'getBindArgumentValue'] + ); + + $abstractCondition->expects($this->once()) + ->method('getMappedSqlField') + ->will($this->returnValue('argument')); + + $abstractCondition->expects($this->once()) + ->method('getOperatorForValidate') + ->will($this->returnValue('>')); + + $abstractCondition->expects($this->at(1)) + ->method('getAttribute') + ->will($this->returnValue('attribute')); + + $abstractCondition->expects($this->at(2)) + ->method('getAttribute') + ->will($this->returnValue('attribute')); + + $abstractCondition->expects($this->once()) + ->method('getBindArgumentValue') + ->will($this->returnValue(10)); + + $conditions = [ + $abstractCondition + ]; + + $collection = $this->createPartialMock( + \Magento\Eav\Model\Entity\Collection\AbstractCollection::class, + [ + 'getResource', + 'getSelect', + 'getStoreId', + 'getDefaultStoreId', + ] + ); + + $combine = $this->createPartialMock(\Magento\Rule\Model\Condition\Combine::class, + [ + 'getConditions', + 'getValue', + 'getAggregator' + ] + ); + $resource = $this->createPartialMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, ['getConnection']); + $select = $this->createPartialMock(\Magento\Framework\DB\Select::class, ['where']); + $select->expects($this->never()) + ->method('where'); + + $connection = $this->getMockForAbstractClass( + \Magento\Framework\DB\Adapter\AdapterInterface::class, + ['quoteInto'], + '', + false + ); + + $connection->expects($this->once()) + ->method('quoteInto') + ->with(' > ?', 10) + ->will($this->returnValue(' > 10')); + + $collection->expects($this->once()) + ->method('getResource') + ->will($this->returnValue($resource)); + + $collection->expects($this->once()) + ->method('getStoreId') + ->willReturn(1); + + $collection->expects($this->once()) + ->method('getDefaultStoreId') + ->willReturn(1); + + $resource->expects($this->once()) + ->method('getConnection') + ->will($this->returnValue($connection)); + + $combine->expects($this->once()) + ->method('getValue') + ->willReturn('attribute'); + + $combine->expects($this->once()) + ->method('getAggregator') + ->willReturn(' AND '); + + $combine->expects($this->at(0)) + ->method('getConditions') + ->will($this->returnValue($conditions)); + + $combine->expects($this->at(1)) + ->method('getConditions') + ->will($this->returnValue($conditions)); + + $combine->expects($this->at(2)) + ->method('getConditions') + ->will($this->returnValue($conditions)); + + $combine->expects($this->at(3)) + ->method('getConditions') + ->will($this->returnValue($conditions)); + + $this->_builder->attachConditionToCollection($collection, $combine); + } } From 5725c92582a43d15dc58b415e90cb2a1e31ea648 Mon Sep 17 00:00:00 2001 From: vprohorov <prohorov.vital@gmail.com> Date: Wed, 5 Sep 2018 05:00:39 +0300 Subject: [PATCH 0021/1158] MAGETWO-62728: My Wishlist - quantity input box issue - Adding maxlength to input validation --- .../Wishlist/view/frontend/templates/item/column/cart.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml index 9ea0d1a823235..e124edc6a43e1 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml @@ -21,7 +21,7 @@ $product = $item->getProduct(); <div class="field qty"> <label class="label" for="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]"><span><?= $block->escapeHtml(__('Qty')) ?></span></label> <div class="control"> - <input type="number" data-role="qty" id="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" class="input-text qty" data-validate="{'required-number':true,'validate-greater-than-zero':true}" + <input type="number" data-role="qty" id="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" class="input-text qty" data-validate="{'required-number':true,'validate-greater-than-zero':true,'maxlength':8}" name="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" value="<?= /* @noEscape */ (int)($block->getAddToCartQty($item) * 1) ?>"> </div> </div> From 335c173deba047e558f44f69f5538f1a5be2b54a Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Wed, 5 Sep 2018 15:13:10 +0200 Subject: [PATCH 0022/1158] Adjusted complexity limiter for developer mode --- .../Framework/GraphQl/Query/QueryComplexityLimiter.php | 10 ++++++---- .../Magento/Framework/GraphQl/Query/QueryProcessor.php | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index d2d9477e67b1e..a144ef8967f17 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -16,6 +16,8 @@ * Sets limits for query complexity. A single GraphQL query can potentially * generate thousands of database operations so, the very complex queries * should be filtered and rejected. + * + * https://github.com/webonyx/graphql-php/blob/master/docs/security.md#query-complexity-analysis */ class QueryComplexityLimiter { @@ -42,15 +44,15 @@ public function __construct( } /** - * @param bool $disableIntrospection + * @param bool $developerMode */ - public function execute(bool $disableIntrospection = false): void + public function execute(bool $developerMode = false): void { - DocumentValidator::addRule(new QueryDepth($this->queryDepth)); DocumentValidator::addRule(new QueryComplexity($this->queryComplexity)); - if ($disableIntrospection) { + if (!$developerMode) { DocumentValidator::addRule(new DisableIntrospection()); + DocumentValidator::addRule(new QueryDepth($this->queryDepth)); } } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index e3a2ea3fa753e..57ff56b665a1e 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -24,7 +24,7 @@ class QueryProcessor /** * @var QueryComplexityLimiter */ - protected $queryComplexityLimiter; + private $queryComplexityLimiter; /** * @param ExceptionFormatter $exceptionFormatter @@ -55,8 +55,8 @@ public function process( array $variableValues = null, string $operationName = null ) : array { - $disableIntrospection = !$this->exceptionFormatter->shouldShowDetail(); - $this->queryComplexityLimiter->execute($disableIntrospection); + $developerMode = !$this->exceptionFormatter->shouldShowDetail(); + $this->queryComplexityLimiter->execute($developerMode); $rootValue = null; return \GraphQL\GraphQL::executeQuery( From 9d244de1504677845aa7ccbf4a61218f851b790b Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Thu, 6 Sep 2018 10:39:17 +0300 Subject: [PATCH 0023/1158] MAGETWO-91650: Translation not working for product alerts - Translate email depending on the store on which the notification button was clicked --- app/code/Magento/ProductAlert/Model/Email.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/ProductAlert/Model/Email.php b/app/code/Magento/ProductAlert/Model/Email.php index 7bc4aba351546..d425a0c6b052c 100644 --- a/app/code/Magento/ProductAlert/Model/Email.php +++ b/app/code/Magento/ProductAlert/Model/Email.php @@ -307,11 +307,7 @@ public function send() return false; } - if ($this->_customer->getStoreId() > 0) { - $store = $this->_storeManager->getStore($this->_customer->getStoreId()); - } else { - $store = $this->_website->getDefaultStore(); - } + $store = $this->_website->getDefaultStore(); $storeId = $store->getId(); if ($this->_type == 'price' && !$this->_scopeConfig->getValue( From 56eee0a9844ed31fbc151e2f84a838466683b956 Mon Sep 17 00:00:00 2001 From: Yurii Borysov <yurii_borysov@epam.com> Date: Thu, 6 Sep 2018 17:52:44 +0300 Subject: [PATCH 0024/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information --- .../Order/View/Info/PaymentDetails.php | 26 +++++++++++++++++++ .../Magento/Authorizenet/Model/Directpost.php | 12 +++++++-- app/code/Magento/Authorizenet/etc/config.xml | 1 + app/code/Magento/Authorizenet/etc/di.xml | 5 ++++ app/code/Magento/Authorizenet/i18n/en_US.csv | 5 ++++ 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php new file mode 100644 index 0000000000000..40bd0f293a5fd --- /dev/null +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Authorizenet\Block\Adminhtml\Order\View\Info; + +use Magento\Framework\Phrase; +use Magento\Payment\Block\ConfigurableInfo; + +/** + * Payment information block for Authorize.net payment method + */ +class PaymentDetails extends ConfigurableInfo +{ + /** + * Returns localized label for payment info block + * + * @param string $field + * @return string | Phrase + */ + protected function getLabel($field) + { + return __($field); + } +} diff --git a/app/code/Magento/Authorizenet/Model/Directpost.php b/app/code/Magento/Authorizenet/Model/Directpost.php index d5c11ab54cd94..c59c44622b8cb 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost.php +++ b/app/code/Magento/Authorizenet/Model/Directpost.php @@ -27,7 +27,7 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra /** * @var string */ - protected $_infoBlockType = \Magento\Payment\Block\Info::class; + protected $_infoBlockType = \Magento\Authorizenet\Block\Adminhtml\Order\View\Info\PaymentDetails::class; /** * Payment Method feature @@ -626,6 +626,14 @@ protected function fillPaymentByResponse(\Magento\Framework\DataObject $payment) $payment->setIsTransactionPending(true) ->setIsFraudDetected(true); } + + $additionalInformationKeys = explode(',', $this->getValue('paymentInfoKeys')); + foreach ($additionalInformationKeys as $paymentInfoKey) { + $paymentInfoValue = $response->getDataByKey($paymentInfoKey); + if($paymentInfoValue !== null) { + $payment->setAdditionalInformation($paymentInfoKey, $paymentInfoValue); + } + } } /** @@ -918,7 +926,7 @@ public function fetchTransactionInfo(\Magento\Payment\Model\InfoInterface $payme $payment->setIsTransactionDenied(true); } $this->addStatusCommentOnUpdate($payment, $response, $transactionId); - return []; + return $response->getData(); } /** diff --git a/app/code/Magento/Authorizenet/etc/config.xml b/app/code/Magento/Authorizenet/etc/config.xml index eacf77cda1e77..3a192646b6f7e 100644 --- a/app/code/Magento/Authorizenet/etc/config.xml +++ b/app/code/Magento/Authorizenet/etc/config.xml @@ -32,6 +32,7 @@ <cgi_url>https://secure.authorize.net/gateway/transact.dll</cgi_url> <cgi_url_td_test_mode>https://apitest.authorize.net/xml/v1/request.api</cgi_url_td_test_mode> <cgi_url_td>https://api2.authorize.net/xml/v1/request.api</cgi_url_td> + <paymentInfoKeys>x_card_type,x_account_number,x_avs_code,x_auth_code,x_response_reason_text,x_cvv2_resp_code</paymentInfoKeys> </authorizenet_directpost> </payment> </default> diff --git a/app/code/Magento/Authorizenet/etc/di.xml b/app/code/Magento/Authorizenet/etc/di.xml index 4beb2456be110..69d24019f2fb7 100644 --- a/app/code/Magento/Authorizenet/etc/di.xml +++ b/app/code/Magento/Authorizenet/etc/di.xml @@ -35,4 +35,9 @@ </argument> </arguments> </type> + <type name="Magento\Authorizenet\Block\Adminhtml\Order\View\Info\PaymentDetails"> + <arguments> + <argument name="config" xsi:type="object">Magento\Authorizenet\Model\Directpost</argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv index bb59afffff2c6..eb22bc4fad311 100644 --- a/app/code/Magento/Authorizenet/i18n/en_US.csv +++ b/app/code/Magento/Authorizenet/i18n/en_US.csv @@ -67,3 +67,8 @@ Debug,Debug "Minimum Order Total","Minimum Order Total" "Maximum Order Total","Maximum Order Total" "Sort Order","Sort Order" +"x_card_type","Credit Card Type" +"x_account_number", "Credit Card Number" +"x_avs_code","AVS Response Code" +"x_auth_code","Processor Authentication Code" +"x_response_reason_text","Processor Response Text" From 0ff4e4ead023aa878823bc6d28aaf74d7851b98d Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Fri, 7 Sep 2018 13:10:46 +0400 Subject: [PATCH 0025/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Remove test from CE --- .../Mftf/Section/AdminSalesConfigSection.xml | 10 ---- .../CheckingGiftOptionsActionGroup.xml | 8 +-- .../Test/Mftf/Data/GiftOptionsData.xml | 13 +--- .../Test/Mftf/Metadata/gift_options-meta.xml | 31 ---------- .../StoreFrontCheckingGiftOptionsTest.xml | 59 ------------------- .../Mftf/Section/MultishippingSection.xml} | 5 +- ...AdminShipmentAddressInformationSection.xml | 3 +- 7 files changed, 9 insertions(+), 120 deletions(-) delete mode 100644 app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml delete mode 100644 app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml rename app/code/Magento/{Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml => Multishipping/Test/Mftf/Section/MultishippingSection.xml} (51%) diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml index aefb7c5441c5b..95a9f75768c62 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml @@ -10,18 +10,8 @@ <element name="enableMAPUseSystemValue" type="checkbox" selector="#sales_msrp_enabled_inherit"/> <element name="enableMAPSelect" type="select" selector="#sales_msrp_enabled"/> <element name="giftOptions" type="select" selector="#sales_gift_options-head"/> - <element name="allowGiftWrappingOnOrderLevel" type="select" selector="#sales_gift_options_wrapping_allow_order"/> - <element name="levelNo" type="select" selector="//select[@id='sales_gift_options_wrapping_allow_order']//option[text()='No']"/> - <element name="levelYes" type="select" selector="//select[@id='sales_gift_options_wrapping_allow_order']//option[text()='Yes']"/> - <element name="allowGiftWrappingForOrderItems" type="select" selector="#sales_gift_options_wrapping_allow_items"/> - <element name="itemsNo" type="select" selector="//select[@id='sales_gift_options_wrapping_allow_items']//option[text()='No']"/> - <element name="itemsYes" type="select" selector="//select[@id='sales_gift_options_wrapping_allow_items']//option[text()='Yes']"/> <element name="allowGiftReceipt" type="select" selector="#sales_gift_options_allow_gift_receipt"/> - <element name="receiptNo" type="select" selector="//select[@id='sales_gift_options_allow_gift_receipt']//option[text()='No']"/> - <element name="receiptYes" type="select" selector="//select[@id='sales_gift_options_allow_gift_receipt']//option[text()='Yes']"/> <element name="allowPrintedCard" type="select" selector="#sales_gift_options_allow_printed_card"/> - <element name="printedCardNo" type="select" selector="//select[@id='sales_gift_options_allow_printed_card']//option[text()='No']"/> - <element name="printedCardYes" type="select" selector="//select[@id='sales_gift_options_allow_printed_card']//option[text()='Yes']"/> <element name="go" type="select" selector="//a[@id='sales_gift_options-head']/ancestor::div[@class='entry-edit-head admin__collapsible-block']"/> </section> </sections> \ No newline at end of file diff --git a/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml b/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml index 05dad757e287f..f81877006c7a6 100644 --- a/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml +++ b/app/code/Magento/GiftMessage/Test/Mftf/ActionGroup/CheckingGiftOptionsActionGroup.xml @@ -7,11 +7,11 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <actionGroup name="CheckingGiftOptionsActionGroup"> - <click stepKey="clickOnCheckoutWithMultipleAddresses" selector="{{StoreFrontShoppingCartSection.checkoutWithMultipleAddresses}}"/> - <waitForPageLoad stepKey="waitForShipToMultipleAddresses"/> - <click stepKey="goToShippingInformation" selector="{{StoreFrontShoppingCartSection.goToShippingInformation}}"/> + <click stepKey="clickOnCheckoutWithMultipleAddresses" selector="{{MultishippingSection.checkoutWithMultipleAddresses}}"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <click stepKey="goToShippingInformation" selector="{{AdminShipmentAddressInformationSection.goToShippingInformation}}"/> <waitForPageLoad stepKey="waitForGiftOption"/> <click stepKey="thickAddGiftOptions" selector="{{GiftOptionsOnFrontSection.giftOptionCheckbox}}"/> <waitForPageLoad stepKey="waitForOptions"/> diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml b/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml index b2bc71b5b7a7b..951bbd3b787b7 100644 --- a/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml +++ b/app/code/Magento/GiftMessage/Test/Mftf/Data/GiftOptionsData.xml @@ -7,15 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="ConfigAllowGiftWrappingForOrderItemsOnly" type="gift_options_config_state"> - <requiredEntity type="wrapping_allow_order">wrappingAllowOrder</requiredEntity> - <requiredEntity type="allow_gift_receipt">allowGiftReceipt</requiredEntity> - <requiredEntity type="allow_printed_card">allowPrintedCard</requiredEntity> - </entity> - <entity name="wrappingAllowOrder" type="wrapping_allow_order"> - <data key="value">0</data> - </entity> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <entity name="allowGiftReceipt" type="allow_gift_receipt"> <data key="value">0</data> </entity> @@ -28,9 +20,6 @@ <requiredEntity type="allow_gift_receipt">defaultAllowGiftReceipt</requiredEntity> <requiredEntity type="allow_printed_card">defaultAllowPrintedCard</requiredEntity> </entity> - <entity name="defaultWrappingAllowOrder" type="wrapping_allow_order"> - <data key="value">1</data> - </entity> <entity name="defaultAllowGiftReceipt" type="allow_gift_receipt"> <data key="value">1</data> </entity> diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml b/app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml deleted file mode 100644 index a32f5694f2470..0000000000000 --- a/app/code/Magento/GiftMessage/Test/Mftf/Metadata/gift_options-meta.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> - <operation name="SalesGiftOptionsConfigState" dataType="gift_options_config_state" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST"> - <object key="groups" dataType="gift_options_config_state"> - <object key="gift_options" dataType="gift_options_config_state"> - <object key="fields" dataType="gift_options_config_state"> - <object key="wrapping_allow_order" dataType="wrapping_allow_order"> - <field key="value">string</field> - </object> - <object key="wrapping_allow_items" dataType="wrapping_allow_items"> - <field key="value">string</field> - </object> - <object key="allow_gift_receipt" dataType="allow_gift_receipt"> - <field key="value">string</field> - </object> - <object key="allow_printed_card" dataType="allow_printed_card"> - <field key="value">string</field> - </object> - </object> - </object> - </object> - </operation> -</operations> diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml b/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml deleted file mode 100644 index 0bb5bf0e71fa8..0000000000000 --- a/app/code/Magento/GiftMessage/Test/Mftf/Test/StoreFrontCheckingGiftOptionsTest.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="StoreFrontCheckingGiftOptionsTest"> - <annotations> - <features value="Gift"/> - <stories value="Checking Gift Options on front end order page"/> - <title value="Checking Gift Options on front end order page"/> - <description value="Admin should be able to control gift options"/> - <severity value="MAJOR"/> - <testCaseId value="MAGETWO-94209"/> - <group value="Gift"/> - </annotations> - <before> - <createData stepKey="category" entity="SimpleSubCategory"/> - <createData stepKey="product1" entity="SimpleProduct"> - <requiredEntity createDataKey="category"/> - </createData> - <createData stepKey="product2" entity="SimpleProduct"> - <requiredEntity createDataKey="category"/> - </createData> - <createData entity="Simple_US_Customer" stepKey="customer"/> - <createData entity="ConfigAllowGiftWrappingForOrderItemsOnly" stepKey="configAllowGiftWrappingForOrderItemsOnly"/> - - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> - <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> - <argument name="Customer" value="$$customer$$"/> - </actionGroup> - - </before> - - <amOnPage url="$$product1.name$$.html" stepKey="goToProduct1"/> - <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProduct1"> - <argument name="productName" value="$$product1.name$$"/> - </actionGroup> - <amOnPage url="$$product2.name$$.html" stepKey="goToProduct2"/> - <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProduct2"> - <argument name="productName" value="$$product2.name$$"/> - </actionGroup> - <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="openCart"/> - <actionGroup ref="CheckingGiftOptionsActionGroup" stepKey="checkGiftOptions"/> - - <after> - <createData entity="DefaultConfigGiftOptions" stepKey="restoreDefaultConfigGiftOptions"/> - <deleteData stepKey="deleteCategory" createDataKey="category"/> - <deleteData stepKey="deleteProduct1" createDataKey="product1"/> - <deleteData stepKey="deleteProduct2" createDataKey="product2"/> - <deleteData stepKey="deleteCustomer" createDataKey="customer"/> - <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> - </after> - </test> -</tests> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml b/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml similarity index 51% rename from app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml rename to app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml index 303c5e526423f..e7d57af1172c6 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/StoreFrontShoppingCartSection.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml @@ -7,9 +7,8 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="StoreFrontShoppingCartSection"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <section name="MultishippingSection"> <element name="checkoutWithMultipleAddresses" type="button" selector="//span[text()='Check Out with Multiple Addresses']"/> - <element name="goToShippingInformation" type="button" selector="//button[@title='Go to Shipping Information']"/> </section> </sections> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml index ea4dde8190bc7..10878310c262f 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml @@ -7,11 +7,12 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <section name="AdminShipmentAddressInformationSection"> <element name="billingAddress" type="text" selector=".order-billing-address address"/> <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> <element name="shippingAddressEdit" type="button" selector=".order-shipping-address .actions a"/> + <element name="goToShippingInformation" type="button" selector="//button[@title='Go to Shipping Information']"/> </section> </sections> From 10765ab93c5336dbab89c71f80a0fe14db9ca38a Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Fri, 7 Sep 2018 14:35:54 +0300 Subject: [PATCH 0026/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fixes after discussion. Added configuration to enable/disable toolbar memorizing. --- .../Block/Product/ProductList/Toolbar.php | 19 ++++---- .../Product/ProductList/ToolbarMemorizer.php | 48 +++++++++++-------- .../Magento/Catalog/etc/adminhtml/system.xml | 6 +++ app/code/Magento/Catalog/etc/config.xml | 1 + 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 0e971dcb5b9f5..e3ed8ef94b74b 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -274,7 +274,7 @@ public function getCurrentOrder() $order = $defaultOrder; } - if ($order != $defaultOrder) { + if ($order != $defaultOrder && $this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::ORDER_PARAM_NAME, $order, $defaultOrder); } @@ -300,7 +300,7 @@ public function getCurrentDirection() $dir = $this->_direction; } - if ($dir != $this->_direction) { + if ($dir != $this->_direction && $this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::DIRECTION_PARAM_NAME, $dir, $this->_direction); } @@ -442,7 +442,7 @@ public function getCurrentMode() $mode = $defaultMode; } - if ($mode != $defaultMode) { + if ($mode != $defaultMode && $this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::MODE_PARAM_NAME, $mode, $defaultMode); } @@ -602,7 +602,7 @@ public function getLimit() $limit = $defaultLimit; } - if ($limit != $defaultLimit) { + if ($limit != $defaultLimit && $this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::LIMIT_PARAM_NAME, $limit, $defaultLimit); } @@ -711,15 +711,18 @@ public function getPagerHtml() public function getWidgetOptionsJson(array $customOptions = []) { $defaultMode = $this->_productListHelper->getDefaultViewMode($this->getModes()); + $defaultDirection = $this->_direction ?: ProductList::DEFAULT_SORT_DIRECTION; + $isMemorizingAllowed = $this->toolbarMemorizer->isMemorizingAllowed(); $options = [ 'mode' => ToolbarModel::MODE_PARAM_NAME, 'direction' => ToolbarModel::DIRECTION_PARAM_NAME, 'order' => ToolbarModel::ORDER_PARAM_NAME, 'limit' => ToolbarModel::LIMIT_PARAM_NAME, - 'modeDefault' => $defaultMode, - 'directionDefault' => $this->_direction ?: ProductList::DEFAULT_SORT_DIRECTION, - 'orderDefault' => $this->getOrderField(), - 'limitDefault' => $this->_productListHelper->getDefaultLimitPerPageValue($defaultMode), + 'modeDefault' => $isMemorizingAllowed ? false : $defaultMode, + 'directionDefault' => $isMemorizingAllowed ? false : $defaultDirection, + 'orderDefault' => $isMemorizingAllowed ? false : $this->getOrderField(), + 'limitDefault' => $isMemorizingAllowed ? false : + $this->_productListHelper->getDefaultLimitPerPageValue($defaultMode), 'url' => $this->getPagerUrl(), ]; $options = array_replace_recursive($options, $customOptions); diff --git a/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php b/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php index 1ff63a0fa3448..4e65a4f9853e7 100644 --- a/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php +++ b/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php @@ -3,9 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Catalog\Model\Product\ProductList; use Magento\Catalog\Model\Session as CatalogSession; +use Magento\Framework\App\Config\ScopeConfigInterface; /** * Class ToolbarMemorizer @@ -14,6 +18,11 @@ */ class ToolbarMemorizer { + /** + * XML PATH to enable/disable saving toolbar parameters to session + */ + const XML_PATH_CATALOG_REMEMBER_PAGINATION = 'catalog/frontend/remember_pagination'; + /** * @var CatalogSession */ @@ -25,9 +34,9 @@ class ToolbarMemorizer private $toolbarModel; /** - * @var bool + * @var ScopeConfigInterface */ - private $paramsMemorizeAllowed = true; + private $scopeConfig; /** * @var string|bool @@ -52,13 +61,16 @@ class ToolbarMemorizer /** * @param Toolbar $toolbarModel * @param CatalogSession $catalogSession + * @param ScopeConfigInterface $scopeConfig */ public function __construct( Toolbar $toolbarModel, - CatalogSession $catalogSession + CatalogSession $catalogSession, + ScopeConfigInterface $scopeConfig ) { $this->toolbarModel = $toolbarModel; $this->catalogSession = $catalogSession; + $this->scopeConfig = $scopeConfig; } /** @@ -118,27 +130,28 @@ public function getLimit() } /** - * Disable list state params memorizing + * Method to save all catalog parameters in catalog session * - * @return $this + * @return void */ - public function disableParamsMemorizing() + public function memorizeParams() { - $this->paramsMemorizeAllowed = false; - return $this; + if (!$this->catalogSession->getParamsMemorizeDisabled() && $this->isMemorizingAllowed()) { + $this->memorizeParam(Toolbar::ORDER_PARAM_NAME, $this->getOrder()) + ->memorizeParam(Toolbar::DIRECTION_PARAM_NAME, $this->getDirection()) + ->memorizeParam(Toolbar::MODE_PARAM_NAME, $this->getMode()) + ->memorizeParam(Toolbar::LIMIT_PARAM_NAME, $this->getLimit()); + } } /** - * Method to save all catalog parameters in catalog session + * Check configuration for enabled/disabled toolbar memorizing * - * @return void + * @return bool */ - public function memorizeParams() + public function isMemorizingAllowed() { - $this->memorizeParam(Toolbar::ORDER_PARAM_NAME, $this->getOrder()) - ->memorizeParam(Toolbar::DIRECTION_PARAM_NAME, $this->getDirection()) - ->memorizeParam(Toolbar::MODE_PARAM_NAME, $this->getMode()) - ->memorizeParam(Toolbar::LIMIT_PARAM_NAME, $this->getLimit()); + return $this->scopeConfig->isSetFlag(self::XML_PATH_CATALOG_REMEMBER_PAGINATION); } /** @@ -150,10 +163,7 @@ public function memorizeParams() */ private function memorizeParam($param, $value) { - if ($value && $this->paramsMemorizeAllowed && - !$this->catalogSession->getParamsMemorizeDisabled() && - $this->catalogSession->getData($param) != $value - ) { + if ($value && $this->catalogSession->getData($param) != $value) { $this->catalogSession->setData($param, $value); } return $this; diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index 71a799fd22427..be35ae2e5549d 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -92,6 +92,12 @@ <comment>Whether to show "All" option in the "Show X Per Page" dropdown</comment> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> </field> + <field id="remember_pagination" translate="label comment" type="select" sortOrder="7" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <label>Remember Category Pagination</label> + <comment>Note that SEO and performance experience may be negative by this feature enabled. + Also it will increase cache storage consumption.</comment> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + </field> </group> <group id="placeholder" translate="label" sortOrder="300" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Product Image Placeholders</label> diff --git a/app/code/Magento/Catalog/etc/config.xml b/app/code/Magento/Catalog/etc/config.xml index 1d92197e390a1..9ede3885f9a78 100644 --- a/app/code/Magento/Catalog/etc/config.xml +++ b/app/code/Magento/Catalog/etc/config.xml @@ -30,6 +30,7 @@ <flat_catalog_category>0</flat_catalog_category> <default_sort_by>position</default_sort_by> <parse_url_directives>1</parse_url_directives> + <remember_pagination>0</remember_pagination> </frontend> <product> <flat> From cd649d162681f3698cb0f989cb624f79ae9f4dfc Mon Sep 17 00:00:00 2001 From: Oleksandr_Hodzevych <Oleksandr_Hodzevych@epam.com> Date: Fri, 7 Sep 2018 15:10:50 +0300 Subject: [PATCH 0027/1158] MAGETWO-91609: Problems with operator more/less in the "catalog Products List" widget - Fixed widget operator less or more --- app/code/Magento/Rule/Model/Condition/Sql/Builder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index 1afe995f837ea..01c671f0b0678 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -32,11 +32,11 @@ class Builder '==' => ':field = ?', '!=' => ':field <> ?', '>=' => ':field >= ?', - '>e;' => ':field >= ?', + '>=' => ':field >= ?', '>' => ':field > ?', '>' => ':field > ?', '<=' => ':field <= ?', - '<e;' => ':field <= ?', + '<=' => ':field <= ?', '<' => ':field < ?', '<' => ':field < ?', '{}' => ':field IN (?)', From 502e415c948db0eaa72ddd1b3dbe57879e0d97f6 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Fri, 7 Sep 2018 17:37:49 +0300 Subject: [PATCH 0028/1158] MAGETWO-91649: #13513: Magento ignore store-level url_key of child category in URL rewrite process for global scope - Fixed issue with incorrect url path generation for children categories; --- .../CategoryUrlPathAutogeneratorObserver.php | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index eb54f0427c11a..5c7a8b16a666e 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -8,6 +8,7 @@ use Magento\Catalog\Model\Category; use Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator; use Magento\CatalogUrlRewrite\Service\V1\StoreViewService; +use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Framework\Event\Observer; use Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider; use Magento\Framework\Event\ObserverInterface; @@ -30,19 +31,27 @@ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface */ protected $storeViewService; + /** + * @var CategoryRepositoryInterface + */ + private $categoryRepository; + /** * @param CategoryUrlPathGenerator $categoryUrlPathGenerator * @param ChildrenCategoriesProvider $childrenCategoriesProvider * @param \Magento\CatalogUrlRewrite\Service\V1\StoreViewService $storeViewService + * @param CategoryRepositoryInterface $categoryRepository */ public function __construct( CategoryUrlPathGenerator $categoryUrlPathGenerator, ChildrenCategoriesProvider $childrenCategoriesProvider, - StoreViewService $storeViewService + StoreViewService $storeViewService, + CategoryRepositoryInterface $categoryRepository ) { $this->categoryUrlPathGenerator = $categoryUrlPathGenerator; $this->childrenCategoriesProvider = $childrenCategoriesProvider; $this->storeViewService = $storeViewService; + $this->categoryRepository = $categoryRepository; } /** @@ -77,22 +86,22 @@ public function execute(\Magento\Framework\Event\Observer $observer) */ protected function updateUrlPathForChildren(Category $category) { - $children = $this->childrenCategoriesProvider->getChildren($category, true); - if ($this->isGlobalScope($category->getStoreId())) { - foreach ($children as $child) { + $childrenIds = $this->childrenCategoriesProvider->getChildrenIds($category, true); + foreach ($childrenIds as $childId) { foreach ($category->getStoreIds() as $storeId) { if ($this->storeViewService->doesEntityHaveOverriddenUrlPathForStore( $storeId, - $child->getId(), + $childId, Category::ENTITY )) { - $child->setStoreId($storeId); + $child = $this->categoryRepository->get($childId, $storeId); $this->updateUrlPathForCategory($child); } } } } else { + $children = $this->childrenCategoriesProvider->getChildren($category, true); foreach ($children as $child) { $child->setStoreId($category->getStoreId()); $this->updateUrlPathForCategory($child); From 87bc13a86363d16bce0f816b35c249174518b70d Mon Sep 17 00:00:00 2001 From: Yurii Borysov <yurii_borysov@epam.com> Date: Mon, 10 Sep 2018 13:32:58 +0300 Subject: [PATCH 0029/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Added CVV2 Response code to i18n file --- app/code/Magento/Authorizenet/i18n/en_US.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv index eb22bc4fad311..6228d5102b13c 100644 --- a/app/code/Magento/Authorizenet/i18n/en_US.csv +++ b/app/code/Magento/Authorizenet/i18n/en_US.csv @@ -72,3 +72,4 @@ Debug,Debug "x_avs_code","AVS Response Code" "x_auth_code","Processor Authentication Code" "x_response_reason_text","Processor Response Text" +"x_cvv2_resp_code","CVV2 Response Code" From 13fa0d74eb5f5fa980d56cead6729c16177e02bc Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Tue, 11 Sep 2018 11:10:13 +0300 Subject: [PATCH 0030/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Add plugin to set toolbar parameters to context before controller dispatch --- .../Block/Product/ProductList/Toolbar.php | 8 +- .../Model/App/Action/ContextPlugin.php | 77 +++++++++++++++++++ app/code/Magento/Catalog/etc/frontend/di.xml | 4 + 3 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index e3ed8ef94b74b..073e3f8f6173e 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -274,7 +274,7 @@ public function getCurrentOrder() $order = $defaultOrder; } - if ($order != $defaultOrder && $this->toolbarMemorizer->isMemorizingAllowed()) { + if ($this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::ORDER_PARAM_NAME, $order, $defaultOrder); } @@ -300,7 +300,7 @@ public function getCurrentDirection() $dir = $this->_direction; } - if ($dir != $this->_direction && $this->toolbarMemorizer->isMemorizingAllowed()) { + if ($this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::DIRECTION_PARAM_NAME, $dir, $this->_direction); } @@ -442,7 +442,7 @@ public function getCurrentMode() $mode = $defaultMode; } - if ($mode != $defaultMode && $this->toolbarMemorizer->isMemorizingAllowed()) { + if ($this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::MODE_PARAM_NAME, $mode, $defaultMode); } @@ -602,7 +602,7 @@ public function getLimit() $limit = $defaultLimit; } - if ($limit != $defaultLimit && $this->toolbarMemorizer->isMemorizingAllowed()) { + if ($this->toolbarMemorizer->isMemorizingAllowed()) { $this->httpContext->setValue(ToolbarModel::LIMIT_PARAM_NAME, $limit, $defaultLimit); } diff --git a/app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php b/app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php new file mode 100644 index 0000000000000..c5ed81540e29e --- /dev/null +++ b/app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Catalog\Model\App\Action; + +use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel; +use Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer; +use Magento\Catalog\Model\Session as CatalogSession; +use Magento\Framework\App\Http\Context as HttpContext; + +/** + * Before dispatch plugin for all frontend controllers to update http context. + */ +class ContextPlugin +{ + /** + * @var ToolbarMemorizer + */ + private $toolbarMemorizer; + + /** + * @var CatalogSession + */ + private $catalogSession; + + /** + * @var HttpContext + */ + private $httpContext; + + /** + * @param ToolbarMemorizer $toolbarMemorizer + * @param CatalogSession $catalogSession + * @param HttpContext $httpContext + */ + public function __construct( + ToolbarMemorizer $toolbarMemorizer, + CatalogSession $catalogSession, + HttpContext $httpContext + ) { + $this->toolbarMemorizer = $toolbarMemorizer; + $this->catalogSession = $catalogSession; + $this->httpContext = $httpContext; + } + + /** + * Update http context with catalog sensitive information. + * + * @return void + */ + public function beforeDispatch() + { + if ($this->toolbarMemorizer->isMemorizingAllowed()) { + $order = $this->catalogSession->getData(ToolbarModel::ORDER_PARAM_NAME); + if ($order) { + $this->httpContext->setValue(ToolbarModel::ORDER_PARAM_NAME, $order, false); + } + $direction = $this->catalogSession->getData(ToolbarModel::DIRECTION_PARAM_NAME); + if ($direction) { + $this->httpContext->setValue(ToolbarModel::DIRECTION_PARAM_NAME, $direction, false); + } + $mode = $this->catalogSession->getData(ToolbarModel::MODE_PARAM_NAME); + if ($mode) { + $this->httpContext->setValue(ToolbarModel::MODE_PARAM_NAME, $mode, false); + } + $limit = $this->catalogSession->getData(ToolbarModel::LIMIT_PARAM_NAME); + if ($limit) { + $this->httpContext->setValue(ToolbarModel::LIMIT_PARAM_NAME, $limit, false); + } + } + } +} diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml index 55098037191e8..a1520b66e83dc 100644 --- a/app/code/Magento/Catalog/etc/frontend/di.xml +++ b/app/code/Magento/Catalog/etc/frontend/di.xml @@ -116,4 +116,8 @@ <plugin name="get_catalog_category_product_index_table_name" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\TableResolver"/> <plugin name="get_catalog_product_price_index_table_name" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"/> </type> + <type name="Magento\Framework\App\Action\AbstractAction"> + <plugin name="catalog_app_action_dispatch_controller_context_plugin" + type="Magento\Catalog\Model\App\Action\ContextPlugin" /> + </type> </config> From 5746734cc6345d6b265b3efc8d9c839778eb48e9 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Tue, 11 Sep 2018 13:53:04 +0300 Subject: [PATCH 0031/1158] MAGETWO-91658: Wrong Checkout Totals Sort Order in cart - Fixed issue with incorrect totals sorting on cart page; --- .../view/frontend/layout/checkout_cart_index.xml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml b/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml index a5d0be503baad..9e86671500c50 100644 --- a/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml +++ b/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml @@ -13,14 +13,10 @@ <item name="components" xsi:type="array"> <item name="block-totals" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="before_grandtotal" xsi:type="array"> - <item name="children" xsi:type="array"> - <item name="discount" xsi:type="array"> - <item name="component" xsi:type="string">Magento_SalesRule/js/view/cart/totals/discount</item> - <item name="config" xsi:type="array"> - <item name="title" xsi:type="string" translate="true">Discount</item> - </item> - </item> + <item name="discount" xsi:type="array"> + <item name="component" xsi:type="string">Magento_SalesRule/js/view/cart/totals/discount</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string" translate="true">Discount</item> </item> </item> </item> From dc878446ec83d88080c81ad71ef6fc986806f173 Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Tue, 11 Sep 2018 19:41:28 +0400 Subject: [PATCH 0032/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Add change related to xsd --- .../GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml b/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml index 9856f009197c1..63243030682bf 100644 --- a/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml +++ b/app/code/Magento/GiftMessage/Test/Mftf/Section/GiftOptionsOnFrontSection.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="GiftOptionsOnFrontSection"> <element name="giftOptionCheckbox" type="text" selector="//span[text()='Add Gift Options']"/> <element name="addGiftOptionsForIndividualItems" type="text" selector="//dt[@class='order-title individual']"/> From ca7932ba5e813967018a5052a763bbe65c9abd66 Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <karen_mkhitaryan@epam.com> Date: Fri, 7 Sep 2018 12:10:46 +0300 Subject: [PATCH 0033/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Remove test from CE --- .../Mftf/Section/AdminShipmentAddressInformationSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml index 3268a6f288371..10878310c262f 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <section name="AdminShipmentAddressInformationSection"> <element name="billingAddress" type="text" selector=".order-billing-address address"/> <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> From ee4e0a11e8a398755d5586082f38c86a5d126462 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Wed, 12 Sep 2018 15:31:24 +0300 Subject: [PATCH 0034/1158] MAGETWO-92179: Fixed incorrect behavior of attribute sets --- .../catalog/product/attribute/set/main.phtml | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml index 54b945b48c104..670a943da0aad 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml @@ -188,6 +188,15 @@ for( j in config[i].children ) { if(config[i].children[j].id) { newNode = new Ext.tree.TreeNode(config[i].children[j]); + + if (typeof newNode.ui.onTextChange === 'function') { + newNode.ui.onTextChange = function (_3, _4, _5) { + if (this.rendered) { + this.textNode.innerText = _4; + } + } + } + } node.appendChild(newNode); newNode.addListener('click', editSet.unregister); } @@ -195,13 +204,20 @@ } } } - } - editSet = function() { - return { - register : function(node) { - editSet.currentNode = node; - }, + + editSet = function () { + return { + register: function (node) { + editSet.currentNode = node; + if (typeof node.ui.onTextChange === 'function') { + node.ui.onTextChange = function (_3, _4, _5) { + if (this.rendered) { + this.textNode.innerText = _4; + } + } + } + }, unregister : function() { editSet.currentNode = false; @@ -293,6 +309,14 @@ allowDrag : true }); + if (typeof newNode.ui.onTextChange === 'function') { + newNode.ui.onTextChange = function (_3, _4, _5) { + if (this.rendered) { + this.textNode.innerText = _4; + } + } + } + TreePanels.root.appendChild(newNode); newNode.addListener('beforemove', editSet.groupBeforeMove); newNode.addListener('beforeinsert', editSet.groupBeforeInsert); From 6d068c79b5bb8fcad3a4b18df2a394fb7beb84f6 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Tue, 11 Sep 2018 18:11:30 +0300 Subject: [PATCH 0035/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Post toolbar parameters when using toolbar saving. --- .../Block/Product/ProductList/Toolbar.php | 29 +++++++++---- .../frontend/web/js/product/list/toolbar.js | 41 ++++++++++++++++--- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 073e3f8f6173e..9f1514aab9d6f 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -8,6 +8,7 @@ use Magento\Catalog\Helper\Product\ProductList; use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel; use Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer; +use Magento\Framework\App\ObjectManager; /** * Product list toolbar @@ -132,6 +133,11 @@ class Toolbar extends \Magento\Framework\View\Element\Template */ private $httpContext; + /** + * @var \Magento\Framework\Data\Form\FormKey + */ + private $formKey; + /** * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Catalog\Model\Session $catalogSession @@ -142,6 +148,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper * @param ToolbarMemorizer|null $toolbarMemorizer * @param \Magento\Framework\App\Http\Context|null $httpContext + * @param \Magento\Framework\Data\Form\FormKey|null $formKey * @param array $data */ public function __construct( @@ -154,6 +161,7 @@ public function __construct( \Magento\Framework\Data\Helper\PostHelper $postDataHelper, ToolbarMemorizer $toolbarMemorizer = null, \Magento\Framework\App\Http\Context $httpContext = null, + \Magento\Framework\Data\Form\FormKey $formKey = null, array $data = [] ) { $this->_catalogSession = $catalogSession; @@ -162,12 +170,15 @@ public function __construct( $this->urlEncoder = $urlEncoder; $this->_productListHelper = $productListHelper; $this->_postDataHelper = $postDataHelper; - $this->toolbarMemorizer = $toolbarMemorizer ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + $this->toolbarMemorizer = $toolbarMemorizer ?: ObjectManager::getInstance()->get( ToolbarMemorizer::class ); - $this->httpContext = $httpContext ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + $this->httpContext = $httpContext ?: ObjectManager::getInstance()->get( \Magento\Framework\App\Http\Context::class ); + $this->formKey = $formKey ?: ObjectManager::getInstance()->get( + \Magento\Framework\Data\Form\FormKey::class + ); parent::__construct($context, $data); } @@ -711,19 +722,19 @@ public function getPagerHtml() public function getWidgetOptionsJson(array $customOptions = []) { $defaultMode = $this->_productListHelper->getDefaultViewMode($this->getModes()); - $defaultDirection = $this->_direction ?: ProductList::DEFAULT_SORT_DIRECTION; - $isMemorizingAllowed = $this->toolbarMemorizer->isMemorizingAllowed(); $options = [ 'mode' => ToolbarModel::MODE_PARAM_NAME, 'direction' => ToolbarModel::DIRECTION_PARAM_NAME, 'order' => ToolbarModel::ORDER_PARAM_NAME, 'limit' => ToolbarModel::LIMIT_PARAM_NAME, - 'modeDefault' => $isMemorizingAllowed ? false : $defaultMode, - 'directionDefault' => $isMemorizingAllowed ? false : $defaultDirection, - 'orderDefault' => $isMemorizingAllowed ? false : $this->getOrderField(), - 'limitDefault' => $isMemorizingAllowed ? false : - $this->_productListHelper->getDefaultLimitPerPageValue($defaultMode), + 'modeDefault' => $defaultMode, + 'directionDefault' => $this->_direction ?: ProductList::DEFAULT_SORT_DIRECTION, + 'orderDefault' => $this->getOrderField(), + 'limitDefault' => $this->_productListHelper->getDefaultLimitPerPageValue($defaultMode), 'url' => $this->getPagerUrl(), + 'formKey' => $this->formKey->getFormKey(), + 'pageParam' => ToolbarModel::PAGE_PARM_NAME, + 'post' => $this->toolbarMemorizer->isMemorizingAllowed() ? true : false ]; $options = array_replace_recursive($options, $customOptions); return json_encode(['productListToolbarForm' => $options]); diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js b/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js index 88be03a04e71a..aee8933194ab1 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js @@ -27,7 +27,10 @@ define([ directionDefault: 'asc', orderDefault: 'position', limitDefault: '9', - url: '' + url: '', + formKey: '', + pageParam: 'p', + post: false }, /** @inheritdoc */ @@ -99,12 +102,38 @@ define([ } paramData[paramName] = paramValue; - if (paramValue == defaultValue) { //eslint-disable-line eqeqeq - delete paramData[paramName]; - } - paramData = $.param(paramData); + if (this.options.post) { + var form = document.createElement('form'); + + var params = [this.options.mode, this.options.direction, this.options.order, this.options.limit]; + for (var key in paramData) { + if (params.indexOf(key) !== -1) { + var input = document.createElement('input'); + input.name = key; + input.value = paramData[key]; + form.appendChild(input); + delete paramData[key]; + } + } + var formKey = document.createElement('input'); + formKey.name = 'form_key'; + formKey.value = this.options.formKey; + form.appendChild(formKey); + + paramData = $.param(paramData); + baseUrl = baseUrl + (paramData.length ? '?' + paramData : ''); - location.href = baseUrl + (paramData.length ? '?' + paramData : ''); + form.action = baseUrl; + form.method = 'POST'; + document.body.appendChild(form); + form.submit(); + } else { + if (paramValue == defaultValue) { //eslint-disable-line eqeqeq + delete paramData[paramName]; + } + paramData = $.param(paramData); + location.href = baseUrl + (paramData.length ? '?' + paramData : ''); + } } }); From b2b611107a9988f69ea95db1b09dbfbfa3770c12 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Wed, 12 Sep 2018 19:20:52 +0300 Subject: [PATCH 0036/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fix tests. --- .../Block/Product/ProductList/Toolbar.php | 1 - .../Block/Product/ProductList/ToolbarTest.php | 25 ++++++++++++++----- .../frontend/web/js/product/list/toolbar.js | 1 - 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 9f1514aab9d6f..3e3f86cd7de01 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -733,7 +733,6 @@ public function getWidgetOptionsJson(array $customOptions = []) 'limitDefault' => $this->_productListHelper->getDefaultLimitPerPageValue($defaultMode), 'url' => $this->getPagerUrl(), 'formKey' => $this->formKey->getFormKey(), - 'pageParam' => ToolbarModel::PAGE_PARM_NAME, 'post' => $this->toolbarMemorizer->isMemorizingAllowed() ? true : false ]; $options = array_replace_recursive($options, $customOptions); diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php index ac963326dbfa1..8282ffa409f9c 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php @@ -18,6 +18,11 @@ class ToolbarTest extends \PHPUnit\Framework\TestCase */ protected $model; + /** + * @var \Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer | \PHPUnit_Framework_MockObject_MockObject + */ + private $memorizer; + /** * @var \Magento\Framework\Url | \PHPUnit_Framework_MockObject_MockObject */ @@ -62,6 +67,13 @@ protected function setUp() 'getLimit', 'getCurrentPage' ]); + $this->memorizer = $this->createPartialMock(\Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer::class, [ + 'getDirection', + 'getOrder', + 'getMode', + 'getLimit', + 'isMemorizingAllowed' + ]); $this->layout = $this->createPartialMock(\Magento\Framework\View\Layout::class, ['getChildName', 'getBlock']); $this->pagerBlock = $this->createPartialMock(\Magento\Theme\Block\Html\Pager::class, [ 'setUseContainer', @@ -116,6 +128,7 @@ protected function setUp() 'context' => $context, 'catalogConfig' => $this->catalogConfig, 'toolbarModel' => $this->model, + 'toolbarMemorizer' => $this->memorizer, 'urlEncoder' => $this->urlEncoder, 'productListHelper' => $this->productListHelper ] @@ -155,7 +168,7 @@ public function testGetPagerEncodedUrl() public function testGetCurrentOrder() { $order = 'price'; - $this->model->expects($this->once()) + $this->memorizer->expects($this->once()) ->method('getOrder') ->will($this->returnValue($order)); $this->catalogConfig->expects($this->once()) @@ -169,7 +182,7 @@ public function testGetCurrentDirection() { $direction = 'desc'; - $this->model->expects($this->once()) + $this->memorizer->expects($this->once()) ->method('getDirection') ->will($this->returnValue($direction)); @@ -183,7 +196,7 @@ public function testGetCurrentMode() $this->productListHelper->expects($this->once()) ->method('getAvailableViewMode') ->will($this->returnValue(['list' => 'List'])); - $this->model->expects($this->once()) + $this->memorizer->expects($this->once()) ->method('getMode') ->will($this->returnValue($mode)); @@ -232,11 +245,11 @@ public function testGetLimit() $mode = 'list'; $limit = 10; - $this->model->expects($this->once()) + $this->memorizer->expects($this->once()) ->method('getMode') ->will($this->returnValue($mode)); - $this->model->expects($this->once()) + $this->memorizer->expects($this->once()) ->method('getLimit') ->will($this->returnValue($limit)); $this->productListHelper->expects($this->once()) @@ -266,7 +279,7 @@ public function testGetPagerHtml() $this->productListHelper->expects($this->exactly(2)) ->method('getAvailableLimit') ->will($this->returnValue([10 => 10, 20 => 20])); - $this->model->expects($this->once()) + $this->memorizer->expects($this->once()) ->method('getLimit') ->will($this->returnValue($limit)); $this->pagerBlock->expects($this->once()) diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js b/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js index aee8933194ab1..7c47f5bd04d5a 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js @@ -29,7 +29,6 @@ define([ limitDefault: '9', url: '', formKey: '', - pageParam: 'p', post: false }, From 00cb15e4f59e6a71dd51b08b3553633eebfebeaf Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Fri, 14 Sep 2018 09:14:40 +0300 Subject: [PATCH 0037/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fix bug when memorizing getting disabled after we have params in session already. --- .../Product/ProductList/ToolbarMemorizer.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php b/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php index 4e65a4f9853e7..9c1a781d594f7 100644 --- a/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php +++ b/app/code/Magento/Catalog/Model/Product/ProductList/ToolbarMemorizer.php @@ -58,6 +58,11 @@ class ToolbarMemorizer */ private $limit; + /** + * @var bool + */ + private $isMemorizingAllowed; + /** * @param Toolbar $toolbarModel * @param CatalogSession $catalogSession @@ -82,7 +87,7 @@ public function getOrder() { if ($this->order === null) { $this->order = $this->toolbarModel->getOrder() ?? - $this->catalogSession->getData(Toolbar::ORDER_PARAM_NAME); + ($this->isMemorizingAllowed() ? $this->catalogSession->getData(Toolbar::ORDER_PARAM_NAME) : null); } return $this->order; } @@ -96,7 +101,7 @@ public function getDirection() { if ($this->direction === null) { $this->direction = $this->toolbarModel->getDirection() ?? - $this->catalogSession->getData(Toolbar::DIRECTION_PARAM_NAME); + ($this->isMemorizingAllowed() ? $this->catalogSession->getData(Toolbar::DIRECTION_PARAM_NAME) : null); } return $this->direction; } @@ -110,7 +115,7 @@ public function getMode() { if ($this->mode === null) { $this->mode = $this->toolbarModel->getMode() ?? - $this->catalogSession->getData(Toolbar::MODE_PARAM_NAME); + ($this->isMemorizingAllowed() ? $this->catalogSession->getData(Toolbar::MODE_PARAM_NAME) : null); } return $this->mode; } @@ -124,7 +129,7 @@ public function getLimit() { if ($this->limit === null) { $this->limit = $this->toolbarModel->getLimit() ?? - $this->catalogSession->getData(Toolbar::LIMIT_PARAM_NAME); + ($this->isMemorizingAllowed() ? $this->catalogSession->getData(Toolbar::LIMIT_PARAM_NAME) : null); } return $this->limit; } @@ -151,7 +156,10 @@ public function memorizeParams() */ public function isMemorizingAllowed() { - return $this->scopeConfig->isSetFlag(self::XML_PATH_CATALOG_REMEMBER_PAGINATION); + if ($this->isMemorizingAllowed === null) { + $this->isMemorizingAllowed = $this->scopeConfig->isSetFlag(self::XML_PATH_CATALOG_REMEMBER_PAGINATION); + } + return $this->isMemorizingAllowed; } /** From 5dbdd4830626d3d944ed1f23e1bfb6fe3a896aea Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 14 Sep 2018 16:45:37 +0300 Subject: [PATCH 0038/1158] MAGETWO-91785: Fixed incorrect order returns request flow --- .../Magento/Sales/Controller/AbstractController/Reorder.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index dd4d73930cc8f..0ba092b57ca2a 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -7,6 +7,7 @@ namespace Magento\Sales\Controller\AbstractController; use Magento\Framework\App\Action; +use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Registry; abstract class Reorder extends Action\Action @@ -40,9 +41,14 @@ public function __construct( * Action for reorder * * @return \Magento\Framework\Controller\ResultInterface + * @throws NotFoundException */ public function execute() { + if (!$this->getRequest()->isPost()) { + throw new NotFoundException(__('Page not Found')); + } + $result = $this->orderLoader->load($this->_request); if ($result instanceof \Magento\Framework\Controller\ResultInterface) { return $result; From 3caa51f14d8f4f84735c87a9da4b7edc27e1c27a Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 14 Sep 2018 16:58:51 +0300 Subject: [PATCH 0039/1158] MAGETWO-91785: Fixed incorrect order returns request flow --- .../Magento/Sales/Controller/AbstractController/Reorder.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index 0ba092b57ca2a..cbc0c2cd007a9 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -4,12 +4,18 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Sales\Controller\AbstractController; use Magento\Framework\App\Action; use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Registry; +/** + * Class Reorder + * + * @package Magento\Sales\Controller\AbstractController + */ abstract class Reorder extends Action\Action { /** From 8aedb958f43bf714c934b677c90d4b74b9d1922b Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Sun, 16 Sep 2018 20:24:39 +0000 Subject: [PATCH 0040/1158] GraphQl-44: prototype of format strategy Signed-off-by: vitaliyboyko <v.boyko@atwix.com> --- ...ibute.php => ProductTextareaAttribute.php} | 25 ++++++---- .../FormatFactory.php | 43 +++++++++++++++++ .../FormatInterface.php | 23 +++++++++ .../Product/ProductTextareaAttribute/Html.php | 47 +++++++++++++++++++ .../CatalogGraphQl/etc/schema.graphqls | 41 +++++++++------- 5 files changed, 152 insertions(+), 27 deletions(-) rename app/code/Magento/CatalogGraphQl/Model/Resolver/Product/{ProductHtmlAttribute.php => ProductTextareaAttribute.php} (67%) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatFactory.php create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatInterface.php create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/Html.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductHtmlAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute.php similarity index 67% rename from app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductHtmlAttribute.php rename to app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute.php index 18d15088e6656..f04609f91c86d 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductHtmlAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute.php @@ -8,38 +8,40 @@ namespace Magento\CatalogGraphQl\Model\Resolver\Product; use Magento\Catalog\Model\Product; +use Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute\FormatFactory; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\Resolver\Value; use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Catalog\Helper\Output as OutputHelper; /** * Resolve rendered content for attributes where HTML content is allowed */ -class ProductHtmlAttribute implements ResolverInterface +class ProductTextareaAttribute implements ResolverInterface { + const DEFAULT_CONTENT_FORMAT_IDENTIFIER = 'html'; + /** * @var ValueFactory */ private $valueFactory; /** - * @var OutputHelper + * @var FormatFactory */ - private $outputHelper; + private $formatFactory; /** * @param ValueFactory $valueFactory - * @param OutputHelper $outputHelper + * @param FormatFactory $formatFactory */ public function __construct( ValueFactory $valueFactory, - OutputHelper $outputHelper + FormatFactory $formatFactory ) { $this->valueFactory = $valueFactory; - $this->outputHelper = $outputHelper; + $this->formatFactory = $formatFactory; } /** @@ -62,9 +64,12 @@ public function resolve( /* @var $product Product */ $product = $value['model']; $fieldName = $field->getName(); - $renderedValue = $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); - $result = function () use ($renderedValue) { - return $renderedValue; + $formatIdentifier = $args['format'] ?? self::DEFAULT_CONTENT_FORMAT_IDENTIFIER; + $format = $this->formatFactory->create($formatIdentifier); + $attribute = ['content' => $format->getContent($product, $fieldName)]; + + $result = function () use ($attribute) { + return $attribute; }; return $this->valueFactory->create($result); diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatFactory.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatFactory.php new file mode 100644 index 0000000000000..2aab2d5816083 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatFactory.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute; + +use Magento\Framework\ObjectManagerInterface; + +class FormatFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * @param string $formatIdentifier + * @param array $data + * @return FormatInterface + */ + public function create(string $formatIdentifier, $data = []) : FormatInterface + { + $formatClassName = 'Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute\\' . ucfirst($formatIdentifier); + $formatInstance = $this->objectManager->create($formatClassName, $data); + if (false == $formatInstance instanceof FormatInterface) { + throw new \InvalidArgumentException( + $formatInstance . ' is not instance of \Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute\FormatInterface' + ); + } + return $formatInstance; + } +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatInterface.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatInterface.php new file mode 100644 index 0000000000000..fae685b75c060 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/FormatInterface.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute; + +use Magento\Catalog\Model\Product as ModelProduct; + +interface FormatInterface +{ + /** + * @param ModelProduct $product + * @param string $fieldName + * @return string + */ + public function getContent( + ModelProduct $product, + string $fieldName + ): string; +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/Html.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/Html.php new file mode 100644 index 0000000000000..8201c40427dc9 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextareaAttribute/Html.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute; + +use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; +use Magento\Catalog\Helper\Output as OutputHelper; +use Magento\Catalog\Model\Product as ModelProduct; + +class Html implements FormatInterface +{ + /** + * @var ValueFactory + */ + private $valueFactory; + + /** + * @var OutputHelper + */ + private $outputHelper; + + /** + * @param ValueFactory $valueFactory + * @param OutputHelper $outputHelper + */ + public function __construct( + ValueFactory $valueFactory, + OutputHelper $outputHelper + ) { + $this->valueFactory = $valueFactory; + $this->outputHelper = $outputHelper; + } + + /** + * @inheritdoc + */ + public function getContent( + ModelProduct $product, + string $fieldName + ): string { + return $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); + } +} \ No newline at end of file diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index f63c1a96762c2..82bc262ecf3c3 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -3,16 +3,16 @@ type Query { products ( - search: String @doc(description: "Performs a full-text search using the specified key words."), - filter: ProductFilterInput @doc(description: "Identifies which product attributes to search for and return."), - pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), - currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), - sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") - ): Products - @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes") + search: String @doc(description: "Performs a full-text search using the specified key words."), + filter: ProductFilterInput @doc(description: "Identifies which product attributes to search for and return."), + pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), + currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), + sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") +): Products + @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes") category ( - id: Int @doc(description: "Id of the category") - ): CategoryTree + id: Int @doc(description: "Id of the category") +): CategoryTree @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") } @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: String @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductHtmlAttribute") - short_description: String @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductHtmlAttribute") + description: ProductTextareaAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") + short_description: ProductTextareaAttribute @doc(description: "A short description of the product. Its use depends on the theme.") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") @@ -377,10 +377,10 @@ interface CategoryInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model product_count: Int @doc(description: "The number of products in the category") default_sort_by: String @doc(description: "The attribute to use for sorting") products( - pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), - currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), - sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") - ): CategoryProducts @doc(description: "The list of products assigned to the category") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\Products") + pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), + currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), + sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") +): CategoryProducts @doc(description: "The list of products assigned to the category") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\Products") breadcrumbs: [Breadcrumb] @doc(description: "Breadcrumbs, parent categories info") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\Breadcrumbs") } @@ -408,8 +408,8 @@ type VirtualProduct implements ProductInterface, CustomizableProductInterface @d } type SimpleProduct implements ProductInterface, PhysicalProductInterface, CustomizableProductInterface @doc(description: "A simple product is tangible and are usually sold as single units or in fixed quantities") -{ -} + { + } type Products @doc(description: "The Products object is the top-level object returned in a product search") { items: [ProductInterface] @doc(description: "An array of products that match the specified search criteria") @@ -551,3 +551,10 @@ type SortFields @doc(description: "SortFields contains a default value for sort default: String @doc(description: "Default value of sort fields") options: [SortField] @doc(description: "Available sort fields") } + +type ProductTextareaAttribute { + content ( + format: String! @doc(description: "The format of content") +): String + @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextareaAttribute") +} From cde04fc296154d8ade7c390b3eb3def76dcc4c02 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Sun, 16 Sep 2018 20:38:50 +0000 Subject: [PATCH 0041/1158] GraphQl-45: pretified schema Signed-off-by: vitaliyboyko <v.boyko@atwix.com> --- .../CatalogGraphQl/etc/schema.graphqls | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 82bc262ecf3c3..a9c4a1b4bd8ae 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -3,16 +3,16 @@ type Query { products ( - search: String @doc(description: "Performs a full-text search using the specified key words."), - filter: ProductFilterInput @doc(description: "Identifies which product attributes to search for and return."), - pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), - currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), - sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") -): Products - @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes") + search: String @doc(description: "Performs a full-text search using the specified key words."), + filter: ProductFilterInput @doc(description: "Identifies which product attributes to search for and return."), + pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), + currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), + sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") + ): Products + @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes") category ( - id: Int @doc(description: "Id of the category") -): CategoryTree + id: Int @doc(description: "Id of the category") + ): CategoryTree @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") } @@ -377,10 +377,10 @@ interface CategoryInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model product_count: Int @doc(description: "The number of products in the category") default_sort_by: String @doc(description: "The attribute to use for sorting") products( - pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), - currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), - sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") -): CategoryProducts @doc(description: "The list of products assigned to the category") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\Products") + pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), + currentPage: Int = 1 @doc(description: "Specifies which page of results to return. The default value is 1."), + sort: ProductSortInput @doc(description: "Specifies which attribute to sort on, and whether to return the results in ascending or descending order.") + ): CategoryProducts @doc(description: "The list of products assigned to the category") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\Products") breadcrumbs: [Breadcrumb] @doc(description: "Breadcrumbs, parent categories info") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\Breadcrumbs") } @@ -408,8 +408,8 @@ type VirtualProduct implements ProductInterface, CustomizableProductInterface @d } type SimpleProduct implements ProductInterface, PhysicalProductInterface, CustomizableProductInterface @doc(description: "A simple product is tangible and are usually sold as single units or in fixed quantities") - { - } +{ +} type Products @doc(description: "The Products object is the top-level object returned in a product search") { items: [ProductInterface] @doc(description: "An array of products that match the specified search criteria") From b1227fc73a76c8dfe7c0af3241b4eeb19e7eb18b Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Mon, 17 Sep 2018 15:18:36 +0200 Subject: [PATCH 0042/1158] Changed query depth limiter behavior --- app/code/Magento/GraphQl/etc/di.xml | 2 +- .../Framework/QueryComplexityLimiterTest.php | 6 +++++- .../GraphQl/Query/QueryComplexityLimiter.php | 14 ++++---------- .../Framework/GraphQl/Query/QueryProcessor.php | 6 ++++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index 529280b7cbb6e..b1d24ce6c4a55 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -99,7 +99,7 @@ </type> <type name="Magento\Framework\GraphQl\Query\QueryComplexityLimiter"> <arguments> - <argument name="queryDepth" xsi:type="number">10</argument> + <argument name="queryDepth" xsi:type="number">15</argument> <argument name="queryComplexity" xsi:type="number">50</argument> </arguments> </type> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php index c5f645a94472a..4616c450786ed 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -9,6 +9,10 @@ use Magento\TestFramework\TestCase\GraphQlAbstract; +/** + * Tests query complexity limiter and depth limiter. + * Actual for production mode only + */ class QueryComplexityLimiterTest extends GraphQlAbstract { /** @@ -159,7 +163,7 @@ public function testQueryDepthIsLimited() } } QUERY; - self::expectExceptionMessageRegExp('/Max query depth should be 10 but got 20/'); + self::expectExceptionMessageRegExp('/Max query depth should be 15 but got 20/'); $this->graphQlQuery($query); } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index a144ef8967f17..15e0edb2400ec 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -36,23 +36,17 @@ class QueryComplexityLimiter * @param int $queryComplexity */ public function __construct( - int $queryDepth = 10, + int $queryDepth = 15, int $queryComplexity = 50 ) { $this->queryDepth = $queryDepth; $this->queryComplexity = $queryComplexity; } - /** - * @param bool $developerMode - */ - public function execute(bool $developerMode = false): void + public function execute(): void { DocumentValidator::addRule(new QueryComplexity($this->queryComplexity)); - - if (!$developerMode) { - DocumentValidator::addRule(new DisableIntrospection()); - DocumentValidator::addRule(new QueryDepth($this->queryDepth)); - } + DocumentValidator::addRule(new DisableIntrospection()); + DocumentValidator::addRule(new QueryDepth($this->queryDepth)); } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index 57ff56b665a1e..98e6c840ba682 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -55,8 +55,10 @@ public function process( array $variableValues = null, string $operationName = null ) : array { - $developerMode = !$this->exceptionFormatter->shouldShowDetail(); - $this->queryComplexityLimiter->execute($developerMode); + var_dump($this->exceptionFormatter->shouldShowDetail()); + if (!$this->exceptionFormatter->shouldShowDetail()) { + $this->queryComplexityLimiter->execute(); + } $rootValue = null; return \GraphQL\GraphQL::executeQuery( From 1a64b7d2396ef7aea3bc59bffbade0727c352c29 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Mon, 17 Sep 2018 16:19:53 +0300 Subject: [PATCH 0043/1158] MAGETWO-91785: Fixed incorrect order returns request flow --- app/code/Magento/Sales/Controller/AbstractController/Reorder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index cbc0c2cd007a9..a96892978c7fb 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ From 57fe7c19716fbc248fb7679063f2c4cd6281b7e6 Mon Sep 17 00:00:00 2001 From: "Hakobyan, Lusine" <Lusine_Hakobyan@epam.com> Date: Mon, 17 Sep 2018 17:24:41 +0400 Subject: [PATCH 0044/1158] MAGETWO-91704: Can't cancel/change payment method after chosen Store Credit - Add locator for automated test --- .../Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml index e4d329bc85057..8aaf626edab33 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml @@ -9,9 +9,10 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderFormPaymentSection"> + <element name="useCustomerBalance" type="checkbox" selector="#p_method_use_customerbalance"/> <element name="header" type="text" selector="#order-methods span.title"/> <element name="getShippingMethods" type="text" selector="#order-shipping_method a.action-default" timeout="30"/> <element name="flatRateOption" type="radio" selector="#s_method_flatrate_flatrate" timeout="30"/> <element name="shippingError" type="text" selector="#order[has_shipping]-error"/> </section> -</sections> \ No newline at end of file +</sections> From b91f5c81dc994d070aca3e7bb453f08cdc8eb756 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 17 Sep 2018 20:29:49 +0300 Subject: [PATCH 0045/1158] GraphQL-133: Complexity limiter prototype --- .../Framework/GraphQl/Query/QueryComplexityLimiter.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index 15e0edb2400ec..b302f4272527a 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -13,6 +13,8 @@ use GraphQL\Validator\Rules\QueryComplexity; /** + * QueryComplexityLimiter + * * Sets limits for query complexity. A single GraphQL query can potentially * generate thousands of database operations so, the very complex queries * should be filtered and rejected. @@ -43,6 +45,11 @@ public function __construct( $this->queryComplexity = $queryComplexity; } + /** + * Sets limits for query complexity + * + * @return void + */ public function execute(): void { DocumentValidator::addRule(new QueryComplexity($this->queryComplexity)); From 341d68cc42e6a06cfdccf2d1fcb4475f69bb9318 Mon Sep 17 00:00:00 2001 From: RomanKis <romaikiss@gmail.com> Date: Tue, 5 Dec 2017 18:01:25 +0200 Subject: [PATCH 0046/1158] MAGETWO-94308: User can place order with amount less than "minimum order amount" via Checkout with multiple address flow. - Upport fix from 2.2-develop --- .../Model/Checkout/Type/Multishipping.php | 53 +++++++++++++++++-- .../Model/Checkout/Type/MultishippingTest.php | 42 ++++++++++++++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index 9412b13895599..8d740b4ea6b92 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -897,13 +897,21 @@ public function reset() */ public function validateMinimumAmount() { - return !($this->_scopeConfig->isSetFlag( + $minimumOrderActive = $this->_scopeConfig->isSetFlag( 'sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ) && $this->_scopeConfig->isSetFlag( + ); + + if ($this->_scopeConfig->isSetFlag( 'sales/minimum_order/multi_address', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ) && !$this->getQuote()->validateMinimumAmount()); + \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ) { + $result = !($minimumOrderActive && !$this->getQuote()->validateMinimumAmount()); + } else { + $result = !($minimumOrderActive && !$this->validateMinimumAmountForAddressItems()); + } + + return $result; } /** @@ -1115,6 +1123,43 @@ private function getShippingAssignmentProcessor() return $this->shippingAssignmentProcessor; } + /** + * Validate minimum amount for "Checkout with Multiple Addresses" when + * "Validate Each Address Separately in Multi-address Checkout" is No. + * + * @return bool + */ + private function validateMinimumAmountForAddressItems() + { + $result = true; + $storeId = $this->getQuote()->getStoreId(); + + $minAmount = $this->_scopeConfig->getValue( + 'sales/minimum_order/amount', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + $storeId + ); + $taxInclude = $this->_scopeConfig->getValue( + 'sales/minimum_order/tax_including', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + $storeId + ); + + $addresses = $this->getQuote()->getAllAddresses(); + + $baseTotal = 0; + foreach ($addresses as $address) { + $taxes = $taxInclude ? $address->getBaseTaxAmount() : 0; + $baseTotal += $address->getBaseSubtotalWithDiscount() + $taxes; + } + + if ($baseTotal < $minAmount) { + $result = false; + } + + return $result; + } + /** * Remove successfully placed items from quote. * diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php index 94c11bef1d311..da206cf266219 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php @@ -167,13 +167,18 @@ class MultishippingTest extends \PHPUnit\Framework\TestCase */ private $sessionMock; + /** + * @var PHPUnit_Framework_MockObject_MockObject + */ + private $scopeConfigMock; + protected function setUp() { $this->checkoutSessionMock = $this->createSimpleMock(Session::class); $this->customerSessionMock = $this->createSimpleMock(CustomerSession::class); $this->orderFactoryMock = $this->createSimpleMock(OrderFactory::class); $eventManagerMock = $this->createSimpleMock(ManagerInterface::class); - $scopeConfigMock = $this->createSimpleMock(ScopeConfigInterface::class); + $this->scopeConfigMock = $this->createSimpleMock(ScopeConfigInterface::class); $this->sessionMock = $this->createSimpleMock(Generic::class); $addressFactoryMock = $this->createSimpleMock(AddressFactory::class); $this->toOrderMock = $this->createSimpleMock(ToOrder::class); @@ -224,7 +229,7 @@ protected function setUp() $this->orderFactoryMock, $this->addressRepositoryMock, $eventManagerMock, - $scopeConfigMock, + $this->scopeConfigMock, $this->sessionMock, $addressFactoryMock, $this->toOrderMock, @@ -807,4 +812,37 @@ private function createSimpleMock($className) ->disableOriginalConstructor() ->getMock(); } + + public function testValidateMinimumAmountMultiAddressTrue() + { + $this->scopeConfigMock->expects($this->exactly(2))->method('isSetFlag')->withConsecutive( + ['sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE], + ['sales/minimum_order/multi_address', \Magento\Store\Model\ScopeInterface::SCOPE_STORE] + )->willReturnOnConsecutiveCalls(true, true); + + $this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($this->quoteMock); + $this->quoteMock->expects($this->once())->method('validateMinimumAmount')->willReturn(false); + $this->assertFalse($this->model->validateMinimumAmount()); + } + + public function testValidateMinimumAmountMultiAddressFalse() + { + $addressMock = $this->createMock(\Magento\Quote\Model\Quote\Address::class); + $this->scopeConfigMock->expects($this->exactly(2))->method('isSetFlag')->withConsecutive( + ['sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE], + ['sales/minimum_order/multi_address', \Magento\Store\Model\ScopeInterface::SCOPE_STORE] + )->willReturnOnConsecutiveCalls(true, false); + + $this->scopeConfigMock->expects($this->exactly(2))->method('getValue')->withConsecutive( + ['sales/minimum_order/amount', \Magento\Store\Model\ScopeInterface::SCOPE_STORE], + ['sales/minimum_order/tax_including', \Magento\Store\Model\ScopeInterface::SCOPE_STORE] + )->willReturnOnConsecutiveCalls(100, false); + + $this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($this->quoteMock); + $this->quoteMock->expects($this->once())->method('getStoreId')->willReturn(1); + $this->quoteMock->expects($this->once())->method('getAllAddresses')->willReturn([$addressMock]); + $addressMock->expects($this->once())->method('getBaseSubtotalWithDiscount')->willReturn(101); + + $this->assertTrue($this->model->validateMinimumAmount()); + } } From e323c7b3661191c9eeb52776ab1b4c0c6fb5d8ad Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Mon, 17 Sep 2018 14:50:10 -0500 Subject: [PATCH 0047/1158] MAGETWO-94308: User can place order with amount less than "minimum order amount" via Checkout with multiple address flow. - Fix issue with upport that doesn't trigger totals to re-calculate before validation - Remove redundant form markup from addresses template - Update unit test to account for changes --- .../Model/Checkout/Type/Multishipping.php | 3 ++- .../Unit/Model/Checkout/Type/MultishippingTest.php | 8 ++++++++ .../view/frontend/templates/checkout/addresses.phtml | 11 ----------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index 8d740b4ea6b92..f55af40388fdf 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -874,7 +874,7 @@ private function logExceptions(array $exceptionList) */ public function save() { - $this->getQuote()->collectTotals(); + $this->getQuote()->setTotalsCollectedFlag(false)->collectTotals(); $this->quoteRepository->save($this->getQuote()); return $this; } @@ -1145,6 +1145,7 @@ private function validateMinimumAmountForAddressItems() $storeId ); + $this->getQuote()->collectTotals(); $addresses = $this->getQuote()->getAllAddresses(); $baseTotal = 0; diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php index da206cf266219..67ff233f717eb 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php @@ -282,6 +282,10 @@ public function testSetShippingItemsInformation() ->willReturn(null); $this->quoteMock->expects($this->atLeastOnce())->method('getAllItems')->willReturn([]); + $this->quoteMock->expects($this->once()) + ->method('__call') + ->with('setTotalsCollectedFlag', [false]) + ->willReturnSelf(); $this->filterBuilderMock->expects($this->atLeastOnce())->method('setField')->willReturnSelf(); $this->filterBuilderMock->expects($this->atLeastOnce())->method('setValue')->willReturnSelf(); @@ -421,6 +425,10 @@ public function testSetShippingMethods() $addressMock->expects($this->once())->method('getId')->willReturn($addressId); $this->quoteMock->expects($this->once())->method('getAllShippingAddresses')->willReturn([$addressMock]); $addressMock->expects($this->once())->method('setShippingMethod')->with($methodsArray[$addressId]); + $this->quoteMock->expects($this->once()) + ->method('__call') + ->with('setTotalsCollectedFlag', [false]) + ->willReturnSelf(); $this->mockShippingAssignment(); diff --git a/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml b/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml index 0f96f7cdb708a..a29013cc71722 100644 --- a/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml +++ b/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml @@ -14,17 +14,6 @@ * @var $block \Magento\Multishipping\Block\Checkout\Addresses */ ?> -<form id="checkout_multishipping_form" - data-mage-init='{ - "multiShipping":{}, - "validation":{}, - "cartUpdate": { - "validationURL": "/multishipping/checkout/checkItems", - "eventName": "updateMulticartItemQty" - }}' - action="<?= $block->escapeUrl($block->getPostActionUrl()) ?>" - method="post" - class="multicheckout address form"> <form id="checkout_multishipping_form" data-mage-init='{ "multiShipping":{}, From 6cc067a431bb9c347c2e174c58b9983c1904e16b Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu <dzmitry_tabusheu@epam.com> Date: Tue, 18 Sep 2018 13:13:29 +0300 Subject: [PATCH 0048/1158] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Added possibility to recalculate tax amounts in case of '0' shipping value refund --- .../Magento/Sales/Model/Order/Creditmemo/Total/Tax.php | 7 ++++++- .../Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index a842c0470ad85..98b854fb07778 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -5,9 +5,14 @@ */ namespace Magento\Sales\Model\Order\Creditmemo\Total; +/** + * Order credit memo tax total calculation model + */ class Tax extends AbstractTotal { /** + * Collect credit memo tax total + * * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return $this * @@ -72,7 +77,7 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $isPartialShippingRefunded = false; if ($invoice = $creditmemo->getInvoice()) { //recalculate tax amounts in case if refund shipping value was changed - if ($order->getBaseShippingAmount() && $creditmemo->getBaseShippingAmount()) { + if ($order->getBaseShippingAmount() && $creditmemo->getBaseShippingAmount() !== null) { $taxFactor = $creditmemo->getBaseShippingAmount() / $order->getBaseShippingAmount(); $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor; $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor; diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php index 4bca669f089b7..565d51ff515a2 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php @@ -447,10 +447,10 @@ public function collectDataProvider() ], ], 'creditmemo_data' => [ - 'grand_total' => 64.95, - 'base_grand_total' => 64.95, - 'tax_amount' => 4.95, - 'base_tax_amount' => 4.95, + 'grand_total' => 64.94, + 'base_grand_total' => 64.94, + 'tax_amount' => 4.94, + 'base_tax_amount' => 4.94, ], ], ]; From 02ab61cc1a9ac377aca9d7b2d488fcd2a3858da6 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Sat, 15 Sep 2018 13:32:00 +0300 Subject: [PATCH 0049/1158] MAGETWO-59265: Import doesn't allow to set default value per store view (dropdown fields) - Changed logic of setting default value of attributes type "select" --- .../Model/Import/Product/Type/AbstractType.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php index afd018f077d20..8b04b7ec3532f 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php @@ -195,6 +195,8 @@ public function __construct( } /** + * Initialize template for error message. + * * @param array $templateCollection * @return $this */ @@ -377,6 +379,8 @@ public function retrieveAttributeFromCache($attributeCode) } /** + * Adding attribute option. + * * In case we've dynamically added new attribute option during import we need to add it to our cache * in order to keep it up to date. * @@ -508,8 +512,10 @@ public function isSuitable() } /** - * Prepare attributes values for save: exclude non-existent, static or with empty values attributes; - * set default values if needed + * Adding default attribute to product before save. + * + * Prepare attributes values for save: exclude non-existent, static or with empty values attributes, + * set default values if needed. * * @param array $rowData * @param bool $withDefaultValue @@ -539,7 +545,8 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe } } elseif (array_key_exists($attrCode, $rowData)) { $resultAttrs[$attrCode] = $rowData[$attrCode]; - } elseif ($withDefaultValue && null !== $attrParams['default_value']) { + } elseif ($withDefaultValue && null !== $attrParams['default_value'] + && 'select' == $attrParams['type'] && null === $rowData['_store']) { $resultAttrs[$attrCode] = $attrParams['default_value']; } } @@ -611,7 +618,8 @@ protected function getProductEntityLinkField() } /** - * Clean cached values + * Clean cached values. + * * @since 100.2.0 */ public function __destruct() From f5aeea6e7ee4f9b8eacb5814830316eff597a06a Mon Sep 17 00:00:00 2001 From: Stsiapan Korf <Stsiapan_Korf@epam.com> Date: Mon, 17 Sep 2018 15:57:28 +0300 Subject: [PATCH 0050/1158] MAGETWO-91639: Tax is added despite customer group changes - Add recollect quote after customer group change --- .../Quote/Plugin/RecollectOnGroupChange.php | 61 +++++++++++++++++++ app/code/Magento/Quote/etc/frontend/di.xml | 3 + 2 files changed, 64 insertions(+) create mode 100644 app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php diff --git a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php new file mode 100644 index 0000000000000..af6599879de50 --- /dev/null +++ b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Quote\Plugin; + +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Customer\Model\ResourceModel\Customer as CustomerResource; +use Magento\Customer\Model\Customer; + +/** + * Recollect quote totals after change customer group + */ +class RecollectOnGroupChange +{ + /** + * @var CartRepositoryInterface + */ + private $cartRepository; + + /** + * @param CartRepositoryInterface $cartRepository + */ + public function __construct( + CartRepositoryInterface $cartRepository + ) { + $this->cartRepository = $cartRepository; + } + + /** + * Recollect totals if customer group change + * + * @param CustomerResource $subject + * @param CustomerResource $result + * @param Customer $customer + * @return CustomerResource + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave(CustomerResource $subject, CustomerResource $result, Customer $customer) + { + if ($customer->getOrigData('group_id') !== null + && $customer->getOrigData('group_id') != $customer->getGroupId() + ) { + try { + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $this->cartRepository->getActiveForCustomer($customer->getId()); + $quote->setCustomerGroupId($customer->getGroupId()); + $quote->collectTotals(); + $this->cartRepository->save($quote); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //no active cart for customer + } + } + + return $result; + } +} diff --git a/app/code/Magento/Quote/etc/frontend/di.xml b/app/code/Magento/Quote/etc/frontend/di.xml index 25acd6763ba56..125afb96f20fd 100644 --- a/app/code/Magento/Quote/etc/frontend/di.xml +++ b/app/code/Magento/Quote/etc/frontend/di.xml @@ -15,4 +15,7 @@ <type name="Magento\Store\Api\StoreCookieManagerInterface"> <plugin name="update_quote_store_after_switch_store_view" type="Magento\Quote\Plugin\UpdateQuoteStore"/> </type> + <type name="Magento\Customer\Model\ResourceModel\Customer"> + <plugin name="cart_recollect_on_group_change" type="Magento\Quote\Plugin\RecollectOnGroupChange"/> + </type> </config> From fc80a85de0d29219660c18c47d36866ab377fc97 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 18 Sep 2018 16:05:52 +0200 Subject: [PATCH 0051/1158] Removed temp debug logic --- lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index 98e6c840ba682..a6ad10dded849 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -55,7 +55,6 @@ public function process( array $variableValues = null, string $operationName = null ) : array { - var_dump($this->exceptionFormatter->shouldShowDetail()); if (!$this->exceptionFormatter->shouldShowDetail()) { $this->queryComplexityLimiter->execute(); } From e5f051c51a6ebdcdf58137691b061548c321b362 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Thu, 13 Sep 2018 17:03:35 +0300 Subject: [PATCH 0052/1158] MAGETWO-91649: #13513: Magento ignore store-level url_key of child category in URL rewrite process for global scope - Fixed an issue with incorect url rewrites generation for children categories; - Modified unit tests for the new functionality; --- .../Category/ChildrenUrlRewriteGenerator.php | 35 ++++++++++++++----- .../ChildrenUrlRewriteGeneratorTest.php | 19 +++++++--- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php index 6aa33f37cd31f..f6049bbff02c4 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php @@ -10,7 +10,11 @@ use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator; use Magento\UrlRewrite\Model\MergeDataProviderFactory; use Magento\Framework\App\ObjectManager; +use Magento\Catalog\Api\CategoryRepositoryInterface; +/** + * Model for generate url rewrites for children categories + */ class ChildrenUrlRewriteGenerator { /** @@ -28,15 +32,22 @@ class ChildrenUrlRewriteGenerator */ private $mergeDataProviderPrototype; + /** + * @var CategoryRepositoryInterface + */ + private $categoryRepository; + /** * @param \Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider $childrenCategoriesProvider * @param \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGeneratorFactory $categoryUrlRewriteGeneratorFactory * @param \Magento\UrlRewrite\Model\MergeDataProviderFactory|null $mergeDataProviderFactory + * @param CategoryRepositoryInterface|null $categoryRepository */ public function __construct( ChildrenCategoriesProvider $childrenCategoriesProvider, CategoryUrlRewriteGeneratorFactory $categoryUrlRewriteGeneratorFactory, - MergeDataProviderFactory $mergeDataProviderFactory = null + MergeDataProviderFactory $mergeDataProviderFactory = null, + CategoryRepositoryInterface $categoryRepository = null ) { $this->childrenCategoriesProvider = $childrenCategoriesProvider; $this->categoryUrlRewriteGeneratorFactory = $categoryUrlRewriteGeneratorFactory; @@ -44,6 +55,8 @@ public function __construct( $mergeDataProviderFactory = ObjectManager::getInstance()->get(MergeDataProviderFactory::class); } $this->mergeDataProviderPrototype = $mergeDataProviderFactory->create(); + $this->categoryRepository = $categoryRepository + ?: ObjectManager::getInstance()->get(CategoryRepositoryInterface::class); } /** @@ -53,18 +66,22 @@ public function __construct( * @param \Magento\Catalog\Model\Category $category * @param int|null $rootCategoryId * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function generate($storeId, Category $category, $rootCategoryId = null) { $mergeDataProvider = clone $this->mergeDataProviderPrototype; - foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) { - $childCategory->setStoreId($storeId); - $childCategory->setData('save_rewrites_history', $category->getData('save_rewrites_history')); - /** @var CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator */ - $categoryUrlRewriteGenerator = $this->categoryUrlRewriteGeneratorFactory->create(); - $mergeDataProvider->merge( - $categoryUrlRewriteGenerator->generate($childCategory, false, $rootCategoryId) - ); + if ($childrenIds = $this->childrenCategoriesProvider->getChildrenIds($category, true)) { + foreach ($childrenIds as $childId) { + /** @var Category $childCategory */ + $childCategory = $this->categoryRepository->get($childId, $storeId); + $childCategory->setData('save_rewrites_history', $category->getData('save_rewrites_history')); + /** @var CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator */ + $categoryUrlRewriteGenerator = $this->categoryUrlRewriteGeneratorFactory->create(); + $mergeDataProvider->merge( + $categoryUrlRewriteGenerator->generate($childCategory, false, $rootCategoryId) + ); + } } return $mergeDataProvider->getData(); diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/ChildrenUrlRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/ChildrenUrlRewriteGeneratorTest.php index 3f641256b1259..f8422c7c05fa6 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/ChildrenUrlRewriteGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/ChildrenUrlRewriteGeneratorTest.php @@ -31,6 +31,9 @@ class ChildrenUrlRewriteGeneratorTest extends \PHPUnit\Framework\TestCase /** @var \PHPUnit_Framework_MockObject_MockObject */ private $serializerMock; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $categoryRepository; + protected function setUp() { $this->serializerMock = $this->getMockBuilder(Json::class) @@ -47,6 +50,9 @@ protected function setUp() $this->categoryUrlRewriteGenerator = $this->getMockBuilder( \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator::class )->disableOriginalConstructor()->getMock(); + $this->categoryRepository = $this->getMockBuilder( + \Magento\Catalog\Model\CategoryRepository::class + )->disableOriginalConstructor()->getMock(); $mergeDataProviderFactory = $this->createPartialMock( \Magento\UrlRewrite\Model\MergeDataProviderFactory::class, ['create'] @@ -59,14 +65,15 @@ protected function setUp() [ 'childrenCategoriesProvider' => $this->childrenCategoriesProvider, 'categoryUrlRewriteGeneratorFactory' => $this->categoryUrlRewriteGeneratorFactory, - 'mergeDataProviderFactory' => $mergeDataProviderFactory + 'mergeDataProviderFactory' => $mergeDataProviderFactory, + 'categoryRepository' => $this->categoryRepository ] ); } public function testNoChildrenCategories() { - $this->childrenCategoriesProvider->expects($this->once())->method('getChildren')->with($this->category, true) + $this->childrenCategoriesProvider->expects($this->once())->method('getChildrenIds')->with($this->category, true) ->will($this->returnValue([])); $this->assertEquals([], $this->childrenUrlRewriteGenerator->generate('store_id', $this->category)); @@ -76,14 +83,16 @@ public function testGenerate() { $storeId = 'store_id'; $saveRewritesHistory = 'flag'; + $childId = 2; $childCategory = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) ->disableOriginalConstructor()->getMock(); - $childCategory->expects($this->once())->method('setStoreId')->with($storeId); $childCategory->expects($this->once())->method('setData') ->with('save_rewrites_history', $saveRewritesHistory); - $this->childrenCategoriesProvider->expects($this->once())->method('getChildren')->with($this->category, true) - ->will($this->returnValue([$childCategory])); + $this->childrenCategoriesProvider->expects($this->once())->method('getChildrenIds')->with($this->category, true) + ->will($this->returnValue([$childId])); + $this->categoryRepository->expects($this->once())->method('get') + ->with($childId, $storeId)->willReturn($childCategory); $this->category->expects($this->any())->method('getData')->with('save_rewrites_history') ->will($this->returnValue($saveRewritesHistory)); $this->categoryUrlRewriteGeneratorFactory->expects($this->once())->method('create') From 1b9ae1174da8a34ac898ea2bc69cfa39f75eb252 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Tue, 18 Sep 2018 15:32:37 +0300 Subject: [PATCH 0053/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fixes according to code review. --- .../Block/Product/ProductList/Toolbar.php | 2 ++ .../Framework}/App/Action/ContextPlugin.php | 28 ++++++++----------- .../Magento/Catalog/etc/adminhtml/system.xml | 3 +- app/code/Magento/Catalog/etc/frontend/di.xml | 2 +- 4 files changed, 16 insertions(+), 19 deletions(-) rename app/code/Magento/Catalog/{Model => Plugin/Framework}/App/Action/ContextPlugin.php (60%) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 3e3f86cd7de01..12c691d1365c3 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -150,6 +150,8 @@ class Toolbar extends \Magento\Framework\View\Element\Template * @param \Magento\Framework\App\Http\Context|null $httpContext * @param \Magento\Framework\Data\Form\FormKey|null $formKey * @param array $data + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\View\Element\Template\Context $context, diff --git a/app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php b/app/code/Magento/Catalog/Plugin/Framework/App/Action/ContextPlugin.php similarity index 60% rename from app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php rename to app/code/Magento/Catalog/Plugin/Framework/App/Action/ContextPlugin.php index c5ed81540e29e..6add542b15554 100644 --- a/app/code/Magento/Catalog/Model/App/Action/ContextPlugin.php +++ b/app/code/Magento/Catalog/Plugin/Framework/App/Action/ContextPlugin.php @@ -6,7 +6,7 @@ declare(strict_types=1); -namespace Magento\Catalog\Model\App\Action; +namespace Magento\Catalog\Plugin\Framework\App\Action; use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel; use Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer; @@ -56,21 +56,17 @@ public function __construct( public function beforeDispatch() { if ($this->toolbarMemorizer->isMemorizingAllowed()) { - $order = $this->catalogSession->getData(ToolbarModel::ORDER_PARAM_NAME); - if ($order) { - $this->httpContext->setValue(ToolbarModel::ORDER_PARAM_NAME, $order, false); - } - $direction = $this->catalogSession->getData(ToolbarModel::DIRECTION_PARAM_NAME); - if ($direction) { - $this->httpContext->setValue(ToolbarModel::DIRECTION_PARAM_NAME, $direction, false); - } - $mode = $this->catalogSession->getData(ToolbarModel::MODE_PARAM_NAME); - if ($mode) { - $this->httpContext->setValue(ToolbarModel::MODE_PARAM_NAME, $mode, false); - } - $limit = $this->catalogSession->getData(ToolbarModel::LIMIT_PARAM_NAME); - if ($limit) { - $this->httpContext->setValue(ToolbarModel::LIMIT_PARAM_NAME, $limit, false); + $params = [ + ToolbarModel::ORDER_PARAM_NAME, + ToolbarModel::DIRECTION_PARAM_NAME, + ToolbarModel::MODE_PARAM_NAME, + ToolbarModel::LIMIT_PARAM_NAME + ]; + foreach ($params as $param) { + $paramValue = $this->catalogSession->getData($param); + if ($paramValue) { + $this->httpContext->setValue($param, $paramValue, false); + } } } } diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index be35ae2e5549d..adfe4c735201c 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -94,8 +94,7 @@ </field> <field id="remember_pagination" translate="label comment" type="select" sortOrder="7" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Remember Category Pagination</label> - <comment>Note that SEO and performance experience may be negative by this feature enabled. - Also it will increase cache storage consumption.</comment> + <comment>Changing may affect SEO and cache storage consumption.</comment> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> </field> </group> diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml index a1520b66e83dc..ee9c5b29da894 100644 --- a/app/code/Magento/Catalog/etc/frontend/di.xml +++ b/app/code/Magento/Catalog/etc/frontend/di.xml @@ -118,6 +118,6 @@ </type> <type name="Magento\Framework\App\Action\AbstractAction"> <plugin name="catalog_app_action_dispatch_controller_context_plugin" - type="Magento\Catalog\Model\App\Action\ContextPlugin" /> + type="Magento\Catalog\Plugin\Framework\App\Action\ContextPlugin" /> </type> </config> From 1992a368332102563331372d2267f633e3752940 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 18 Sep 2018 17:32:06 +0200 Subject: [PATCH 0054/1158] Travis api-functional testsuite check --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cc730ca5a2cd4..e909bb1980752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ env: - TEST_SUITE=integration INTEGRATION_INDEX=2 - TEST_SUITE=integration INTEGRATION_INDEX=3 - TEST_SUITE=functional + - TEST_SUITE=api-functional matrix: exclude: - php: 7.1 From 0c7edc5a71a02bcc6df929ac0d0f7518b18a376b Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Tue, 18 Sep 2018 20:35:30 +0400 Subject: [PATCH 0055/1158] MAGETWO-91617: Ordered Products Report Error for restricted scope admin - Add some helpers for automated test --- .../ActionGroup/AdminProductActionGroup.xml | 17 +++++++- ...omerWithWebsiteAndStoreViewActionGroup.xml | 43 +++++++++++++++++++ .../AdminDeleteCustomerActionGroup.xml | 23 ++++++++++ .../Customer/Test/Mftf/Data/AddressData.xml | 1 + ...AdminCustomerAccountInformationSection.xml | 1 + .../Section/AdminCustomerAddressesSection.xml | 24 +++++++++++ .../AdminCustomerGridMainActionsSection.xml | 2 + .../AdminReviewOrderActionGroup.xml | 24 +++++++++++ .../Mftf/Section/OrderedProductsSection.xml | 17 ++++++++ .../ActionGroup/AdminOrderActionGroup.xml | 24 +++++++++++ .../AdminInvoicePaymentShippingSection.xml | 2 + .../AdminOrderStoreScopeTreeSection.xml | 1 + .../Mftf/Section/AdminOrdersGridSection.xml | 2 + .../Test/Mftf/Section/OrdersGridSection.xml | 3 +- .../Store/Test/Mftf/Data/StoreData.xml | 12 ++++++ .../AdminCreateUserActionGroup.xml | 23 ++++++++++ .../AdminDeleteCreatedUserActionGroup.xml | 23 ++++++++++ 17 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerWithWebsiteAndStoreViewActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml create mode 100644 app/code/Magento/Reports/Test/Mftf/ActionGroup/AdminReviewOrderActionGroup.xml create mode 100644 app/code/Magento/Reports/Test/Mftf/Section/OrderedProductsSection.xml create mode 100644 app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteCreatedUserActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index 9f8d827b20849..91141a573cf5b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -276,5 +276,20 @@ <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="acceptStoreSwitchingMessage"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> - + <actionGroup name="CreatedProductConnectToWebsite"> + <arguments> + <argument name="website"/> + <argument name="product"/> + </arguments> + <amOnPage url="{{AdminCatalogProductPage.url}}" stepKey="navigateToProductPage"/> + <waitForPageLoad stepKey="waitForProductsList"/> + <click stepKey="openProduct" selector="{{AdminProductGridActionSection.productName(product.name)}}"/> + <waitForPageLoad stepKey="waitForProductPage"/> + <scrollTo selector="{{ProductInWebsitesSection.sectionHeader}}" stepKey="ScrollToWebsites"/> + <click selector="{{ProductInWebsitesSection.sectionHeader}}" stepKey="openWebsitesList"/> + <waitForPageLoad stepKey="waitForWebsitesList"/> + <click selector="{{ProductInWebsitesSection.website(website.name)}}" stepKey="SelectWebsite"/> + <click selector="{{AdminProductFormAdvancedPricingSection.save}}" stepKey="clickSaveProduct"/> + <waitForPageLoad stepKey="waitForSave"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerWithWebsiteAndStoreViewActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerWithWebsiteAndStoreViewActionGroup.xml new file mode 100644 index 0000000000000..0071acf2ef1e0 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerWithWebsiteAndStoreViewActionGroup.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateCustomerWithWebsiteAndStoreViewActionGroup"> + <arguments> + <argument name="customerData"/> + <argument name="address"/> + <argument name="website" type="string"/> + <argument name="storeView" type="string"/> + </arguments> + <amOnPage url="{{AdminCustomerPage.url}}" stepKey="goToCustomersPage"/> + <click stepKey="addNewCustomer" selector="{{AdminCustomerGridMainActionsSection.addNewCustomer}}"/> + <selectOption stepKey="selectWebSite" selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" userInput="{{website}}"/> + <fillField stepKey="FillFirstName" selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{customerData.firstname}}"/> + <fillField stepKey="FillLastName" selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{customerData.lastname}}"/> + <fillField stepKey="FillEmail" selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{customerData.email}}"/> + <selectOption stepKey="selectStoreView" selector="{{AdminCustomerAccountInformationSection.storeView}}" userInput="{{storeView}}"/> + <scrollToTopOfPage stepKey="scrollToTopOfThePage"/> + <click stepKey="goToAddresses" selector="{{AdminCustomerAccountInformationSection.addressesButton}}"/> + <waitForPageLoad stepKey="waitForAddresses"/> + <click stepKey="clickOnAddNewAddress" selector="{{AdminCustomerAddressesSection.addNewAddress}}"/> + <waitForPageLoad stepKey="waitForAddressFields"/> + <click stepKey="thickBillingAddress" selector="{{AdminCustomerAddressesSection.defaultBillingAddress}}"/> + <click stepKey="thickShippingAddress" selector="{{AdminCustomerAddressesSection.defaultShippingAddress}}"/> + <fillField stepKey="fillFirstNameForAddress" selector="{{AdminCustomerAddressesSection.firstNameForAddress}}" userInput="{{address.firstname}}"/> + <fillField stepKey="fillLastNameForAddress" selector="{{AdminCustomerAddressesSection.lastNameForAddress}}" userInput="{{address.lastname}}"/> + <fillField stepKey="fillStreetAddress" selector="{{AdminCustomerAddressesSection.streetAddress}}" userInput="{{address.street[0]}}"/> + <fillField stepKey="fillCity" selector="{{AdminCustomerAddressesSection.city}}" userInput="{{address.city}}"/> + <selectOption stepKey="selectCountry" selector="{{AdminCustomerAddressesSection.country}}" userInput="{{address.country}}"/> + <selectOption stepKey="selectState" selector="{{AdminCustomerAddressesSection.state}}" userInput="{{address.state}}"/> + <fillField stepKey="fillZip" selector="{{AdminCustomerAddressesSection.zip}}" userInput="{{address.postcode}}"/> + <fillField stepKey="fillPhoneNumber" selector="{{AdminCustomerAddressesSection.phoneNumber}}" userInput="{{address.telephone}}"/> + <click stepKey="save" selector="{{AdminCustomerAccountInformationSection.saveCustomer}}"/> + <waitForPageLoad stepKey="waitForCustomersPage"/> + <see stepKey="seeSuccessMessage" userInput="You saved the customer."/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerActionGroup.xml new file mode 100644 index 0000000000000..68f6b49e80996 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCustomerActionGroup"> + <arguments> + <argument name="customerEmail"/> + </arguments> + <amOnPage url="{{AdminCustomerPage.url}}" stepKey="navigateToCustomersPage"/> + <click stepKey="chooseCustomer" selector="{{AdminCustomerGridMainActionsSection.customerCheckbox(customerEmail)}}"/> + <click stepKey="openActions" selector="{{AdminCustomerGridMainActionsSection.actions}}"/> + <waitForPageLoad stepKey="waitActions"/> + <click stepKey="delete" selector="{{AdminCustomerGridMainActionsSection.delete}}"/> + <waitForPageLoad stepKey="waitForConfirmationAlert"/> + <click stepKey="accept" selector="{{AdminCustomerGridMainActionsSection.ok}}"/> + <see stepKey="seeSuccessMessage" userInput="were deleted."/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index d090620145105..033add209a4c2 100755 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -65,6 +65,7 @@ <data key="default_billing">Yes</data> <data key="default_shipping">Yes</data> <requiredEntity type="region">RegionNY</requiredEntity> + <data key="country">United States</data> </entity> <entity name="US_Address_CA" type="address"> <data key="firstname">John</data> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml index 32746a66621eb..8510fd385f92b 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml @@ -11,6 +11,7 @@ <section name="AdminCustomerAccountInformationSection"> <element name="accountInformationTitle" type="text" selector=".admin__page-nav-title"/> <element name="accountInformationButton" type="text" selector="//a/span[text()='Account Information']"/> + <element name="addressesButton" type="select" selector="//a//span[contains(text(), 'Addresses')]"/> <element name="firstName" type="input" selector="input[name='customer[firstname]']"/> <element name="lastName" type="input" selector="input[name='customer[lastname]']"/> <element name="email" type="input" selector="input[name='customer[email]']"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml new file mode 100644 index 0000000000000..175c7ab573d37 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCustomerAddressesSection"> + <element name="addNewAddress" type="button" selector="//span[text()='Add New Addresses']"/> + <element name="defaultBillingAddress" type="button" selector="//label[text()='Default Billing Address']"/> + <element name="defaultShippingAddress" type="button" selector="//label[text()='Default Shipping Address']"/> + <element name="firstNameForAddress" type="button" selector="//input[contains(@name, 'address')][contains(@name, 'firstname')]"/> + <element name="lastNameForAddress" type="button" selector="//input[contains(@name, 'address')][contains(@name, 'lastname')]"/> + <element name="streetAddress" type="button" selector="//input[contains(@name, 'street')]"/> + <element name="city" type="input" selector="//input[contains(@name, 'city')]"/> + <element name="country" type="select" selector="//select[contains(@name, 'country_id')]"/> + <element name="state" type="select" selector="//select[contains(@name, 'address[new_0][region_id]')]"/> + <element name="zip" type="input" selector="//input[contains(@name, 'postcode')]"/> + <element name="phoneNumber" type="input" selector="//input[contains(@name, 'telephone')]"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridMainActionsSection.xml index 1f0c4b4998a9f..d644b581088bc 100755 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridMainActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridMainActionsSection.xml @@ -13,5 +13,7 @@ <element name="multicheck" type="checkbox" selector="#container>div>div.admin__data-grid-wrap>table>thead>tr>th.data-grid-multicheck-cell>div>label"/> <element name="delete" type="button" selector="//*[contains(@class, 'admin__data-grid-header')]//span[contains(@class,'action-menu-item') and text()='Delete']"/> <element name="actions" type="text" selector=".action-select"/> + <element name="customerCheckbox" type="button" selector="//*[contains(text(),'{{arg}}')]/parent::td/preceding-sibling::td/label[@class='data-grid-checkbox-cell-inner']//input" parameterized="true"/> + <element name="ok" type="button" selector="//button[@data-role='action']//span[text()='OK']"/> </section> </sections> diff --git a/app/code/Magento/Reports/Test/Mftf/ActionGroup/AdminReviewOrderActionGroup.xml b/app/code/Magento/Reports/Test/Mftf/ActionGroup/AdminReviewOrderActionGroup.xml new file mode 100644 index 0000000000000..003a5e6655f34 --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/ActionGroup/AdminReviewOrderActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminReviewOrderActionGroup"> + <arguments> + <argument name="productName" type="string"/> + </arguments> + <click stepKey="openReports" selector="{{OrderedProductsSection.reports}}"/> + <waitForPageLoad stepKey="waitForReports" time="5"/> + <click stepKey="openOrdered" selector="{{OrderedProductsSection.ordered}}"/> + <waitForPageLoad stepKey="waitForOrdersPage" time="5"/> + <click stepKey="refresh" selector="{{OrderedProductsSection.refresh}}"/> + <waitForPageLoad stepKey="waitForOrderList" time="5"/> + <scrollTo stepKey="scrollTo" selector="{{OrderedProductsSection.total}}"/> + <see stepKey="seeOrder" userInput="{{productName}}"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Reports/Test/Mftf/Section/OrderedProductsSection.xml b/app/code/Magento/Reports/Test/Mftf/Section/OrderedProductsSection.xml new file mode 100644 index 0000000000000..89e8497dddcea --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/Section/OrderedProductsSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="OrderedProductsSection"> + <element name="reports" type="button" selector="//li[@data-ui-id='menu-magento-reports-report']"/> + <element name="ordered" type="button" selector="//li[@data-ui-id='menu-magento-reports-report-products-sold']"/> + <element name="refresh" type="button" selector="//button[@title='Refresh']" timeout="30"/> + <element name="total" type="text" selector="//tfoot//th[contains(text(), 'Total')]"/> + </section> +</sections> \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index c82623632d782..ffa6a2a5f2d99 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -268,4 +268,28 @@ <see selector="{{AdminMessagesSection.success}}" userInput="You canceled the order." stepKey="seeCancelSuccessMessage"/> <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Canceled" stepKey="seeOrderStatusCanceled"/> </actionGroup> + + <actionGroup name="CreateOrderInStoreActionGroup"> + <arguments> + <argument name="product"/> + <argument name="customer"/> + <argument name="storeView"/> + </arguments> + <amOnPage stepKey="navigateToNewOrderPage" url="{{AdminOrderCreatePage.url}}"/> + <click stepKey="chooseCustomer" selector="{{AdminOrdersGridSection.customerInOrdersSection(customer.firstname)}}"/> + <waitForPageLoad stepKey="waitForStoresPageOpened"/> + <click stepKey="chooseStore" selector="{{AdminOrderStoreScopeTreeSection.storeForOrder(storeView.name)}}"/> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click selector="{{OrdersGridSection.addProducts}}" stepKey="clickOnAddProducts"/> + <waitForPageLoad stepKey="waitForProductsListForOrder"/> + <click selector="{{AdminOrdersGridSection.productForOrder(product.sku)}}" stepKey="chooseTheProduct"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="addSelectedProductToOrder"/> + <waitForPageLoad stepKey="waitForProductAddedInOrder"/> + <click selector="{{AdminInvoicePaymentShippingSection.getShippingMethodAndRates}}" stepKey="openShippingMethod"/> + <waitForPageLoad stepKey="waitForShippingMethods"/> + <click selector="{{AdminInvoicePaymentShippingSection.shippingMethod}}" stepKey="chooseShippingMethod"/> + <waitForPageLoad stepKey="waitForShippingMethodsThickened"/> + <click selector="{{OrdersGridSection.submitOrder}}" stepKey="submitOrder"/> + <see stepKey="seeSuccessMessageForOrder" userInput="You created the order."/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoicePaymentShippingSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoicePaymentShippingSection.xml index 918a8e814b555..8d7c64733972e 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoicePaymentShippingSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoicePaymentShippingSection.xml @@ -15,5 +15,7 @@ <element name="ShippingMethod" type="text" selector=".order-shipping-address .shipping-description-title"/> <element name="ShippingPrice" type="text" selector=".order-shipping-address .shipping-description-content .price"/> <element name="CreateShipment" type="checkbox" selector=".order-shipping-address input[name='invoice[do_shipment]']"/> + <element name="getShippingMethodAndRates" type="button" selector="//span[text()='Get shipping methods and rates']"/> + <element name="shippingMethod" type="button" selector="//label[contains(text(), 'Fixed')]"/> </section> </sections> \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml index 050e1ba8b2df4..cbe17499319f9 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml @@ -11,5 +11,6 @@ <section name="AdminOrderStoreScopeTreeSection"> <element name="storeTree" type="text" selector="div.tree-store-scope"/> <element name="storeOption" type="radio" selector="//div[contains(@class, 'tree-store-scope')]//label[contains(text(), '{{name}}')]/preceding-sibling::input" parameterized="true" timeout="30"/> + <element name="storeForOrder" type="radio" selector="//div[contains(@class, 'tree-store-scope')]//label[contains(text(), '{{arg}}')]" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index 7ece18fb863b7..53a6cbffcdac6 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -29,5 +29,7 @@ <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> <element name="columnsDropdown" type="button" selector="div.admin__data-grid-action-columns button" timeout="30"/> <element name="viewColumnCheckbox" type="checkbox" selector="//div[contains(@class,'admin__data-grid-action-columns')]//div[contains(@class, 'admin__field-option')]//label[text() = '{{column}}']/preceding-sibling::input" parameterized="true"/> + <element name="customerInOrdersSection" type="button" selector="(//td[contains(text(),'{{customer}}')])[1]" parameterized="true"/> + <element name="productForOrder" type="button" selector="//td[contains(text(),'{{var}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml index 8d99bf4872d0a..717022322698f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml @@ -18,7 +18,7 @@ <element name="createNewOrder" type="button" selector="button[title='Create New Order'"/> <element name="website" type="radio" selector="//label[contains(text(), '{{arg}}')]" parameterized="true"/> - <element name="addProducts" type="button" selector="//span[text()='Add Products']"/> + <element name="addProducts" type="button" selector="#add_products"/> <element name="selectProduct" type="checkbox" selector="//td[contains(text(), '{{arg}}')]/following-sibling::td[contains(@class, 'col-select col-in_products')]" parameterized="true"/> <element name="setQuantity" type="checkbox" selector="//td[contains(text(), '{{arg}}')]/following-sibling::td[contains(@class, 'col-qty')]/input" parameterized="true"/> <element name="addProductsToOrder" type="button" selector="//span[text()='Add Selected Product(s) to Order']"/> @@ -29,5 +29,6 @@ <element name="productPrice" type="text" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td[@class='col-price col-row-subtotal']/span" parameterized="true"/> <element name="removeItems" type="select" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td/select[@class='admin__control-select']" parameterized="true"/> <element name="applyCoupon" type="input" selector="#coupons:code"/> + <element name="submitOrder" type="button" selector="#submit_order_top_button"/> </section> </sections> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml index 2bff20e05435a..b0f04dbe703a9 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml @@ -49,4 +49,16 @@ <data key="store_type">store</data> <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> </entity> + <entity name="NewStoreData" type="store"> + <data key="name" unique="suffix">Store</data> + <data key="code" unique="suffix">StoreCode</data> + </entity> + <entity name="NewWebSiteData" type="webSite"> + <data key="name" unique="suffix">WebSite</data> + <data key="code" unique="suffix">WebSiteCode</data> + </entity> + <entity name="NewStoreViewData"> + <data key="name" unique="suffix">StoreView</data> + <data key="code" unique="suffix">StoreViewCode</data> + </entity> </entities> diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml index de887d2de6704..9a0fa4a205799 100644 --- a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml @@ -31,4 +31,27 @@ <waitForPageLoad stepKey="waitForPageLoad2" /> <see userInput="You saved the user." stepKey="seeSuccessMessage" /> </actionGroup> + + <!--Create new user with role--> + <actionGroup name="AdminCreateUserWithRoleActionGroup"> + <arguments> + <argument name="role"/> + <argument name="user" defaultValue="newAdmin"/> + </arguments> + <amOnPage url="{{AdminEditUserPage.url}}" stepKey="navigateToNewUser"/> + <waitForPageLoad stepKey="waitForUsersPage" /> + <fillField selector="{{AdminCreateUserSection.usernameTextField}}" userInput="{{user.username}}" stepKey="enterUserName" /> + <fillField selector="{{AdminCreateUserSection.firstNameTextField}}" userInput="{{user.firstName}}" stepKey="enterFirstName" /> + <fillField selector="{{AdminCreateUserSection.lastNameTextField}}" userInput="{{user.lastName}}" stepKey="enterLastName" /> + <fillField selector="{{AdminCreateUserSection.emailTextField}}" userInput="{{user.username}}@magento.com" stepKey="enterEmail" /> + <fillField selector="{{AdminCreateUserSection.passwordTextField}}" userInput="{{user.password}}" stepKey="enterPassword" /> + <fillField selector="{{AdminCreateUserSection.pwConfirmationTextField}}" userInput="{{user.password}}" stepKey="confirmPassword" /> + <fillField selector="{{AdminCreateUserSection.currentPasswordField}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}" stepKey="enterCurrentPassword" /> + <scrollToTopOfPage stepKey="scrollToTopOfPage" /> + <click stepKey="clickUserRole" selector="{{AdminCreateUserSection.userRoleTab}}"/> + <click stepKey="chooseRole" selector="{{AdminStoreSection.createdRoleInUserPage(role.name)}}"/> + <click selector="{{AdminCreateUserSection.saveButton}}" stepKey="clickSaveUser" /> + <waitForPageLoad stepKey="waitForSaveTheUser" /> + <see userInput="You saved the user." stepKey="seeSuccessMessage" /> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteCreatedUserActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteCreatedUserActionGroup.xml new file mode 100644 index 0000000000000..7f1ed3be1ca57 --- /dev/null +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteCreatedUserActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCreatedUserActionGroup"> + <arguments> + <argument name="user"/> + </arguments> + <amOnPage stepKey="amOnAdminUsersPage" url="{{AdminUsersPage.url}}"/> + <click stepKey="openTheUser" selector="{{AdminDeleteUserSection.role(user.username)}}"/> + <fillField stepKey="TypeCurrentPassword" selector="{{AdminDeleteUserSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click stepKey="clickToDeleteUser" selector="{{AdminDeleteUserSection.delete}}"/> + <waitForPageLoad stepKey="waitForConfirmationPopup"/> + <click stepKey="clickToConfirm" selector="{{AdminDeleteUserSection.confirm}}"/> + <see stepKey="seeDeleteMessageForUser" userInput="You deleted the user."/> + </actionGroup> +</actionGroups> From 96092708fc5156ec967b3aa5d1704b86fcd65611 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Tue, 18 Sep 2018 15:41:25 -0500 Subject: [PATCH 0056/1158] MAGETWO-94308: User can place order with amount less than "minimum order amount" via Checkout with multiple address flow. - Extract config value to variable to resolve code style error --- .../Multishipping/Model/Checkout/Type/Multishipping.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index a30acdc3943ee..d1df064f57140 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -904,10 +904,12 @@ public function validateMinimumAmount() \Magento\Store\Model\ScopeInterface::SCOPE_STORE ); - if ($this->_scopeConfig->isSetFlag( + $minimumOrderMultiFlag = $this->_scopeConfig->isSetFlag( 'sales/minimum_order/multi_address', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE) - ) { + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + if ($minimumOrderMultiFlag) { $result = !($minimumOrderActive && !$this->getQuote()->validateMinimumAmount()); } else { $result = !($minimumOrderActive && !$this->validateMinimumAmountForAddressItems()); From 1e4dd7d86305c48709001082c4865b3460161cbd Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Wed, 19 Sep 2018 00:39:10 +0300 Subject: [PATCH 0057/1158] Clean code --- .../Catalog/Ui/Component/ColumnFactory.php | 20 +- .../Component/Listing/Columns/Thumbnail.php | 2 +- .../Model/ObjectRegistry.php | 6 +- .../Block/Adminhtml/Edit/Tab/View/Sales.php | 18 +- .../Model/Address/AbstractAddress.php | 2 +- app/code/Magento/Fedex/Model/Carrier.php | 13 +- .../IntegrationFactory.php | 2 +- .../DataProvider/NotificationDataProvider.php | 2 +- .../Magento/Sales/Model/Order/Address.php | 2 +- .../Sales/Model/Order/Payment/Info.php | 2 +- .../Sales/Model/Order/Payment/Transaction.php | 4 +- .../Model/ResourceModel/AbstractGrid.php | 2 +- .../Model/Carrier/AbstractCarrierOnline.php | 6 +- .../Request/AddressBuilder.php | 2 +- app/code/Magento/Store/Model/Store.php | 189 ++++++++++-------- .../Model/ResourceModel/Layout/Update.php | 34 ++-- 16 files changed, 168 insertions(+), 138 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php index cbc67fee8a5a3..8daec1fa6ca78 100644 --- a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php +++ b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php @@ -46,12 +46,14 @@ public function __construct(\Magento\Framework\View\Element\UiComponentFactory $ $this->componentFactory = $componentFactory; } - /** - * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute - * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context - * @param array $config - * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface - */ + /** + * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context + * @param array $config + * + * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface + * @throws \Magento\Framework\Exception\LocalizedException + */ public function create($attribute, $context, array $config = []) { $columnName = $attribute->getAttributeCode(); @@ -96,9 +98,7 @@ protected function getJsComponent($dataType) */ protected function getDataType($attribute) { - return isset($this->dataTypeMap[$attribute->getFrontendInput()]) - ? $this->dataTypeMap[$attribute->getFrontendInput()] - : $this->dataTypeMap['default']; + return $this->dataTypeMap[$attribute->getFrontendInput()] ?? $this->dataTypeMap['default']; } /** @@ -111,6 +111,6 @@ protected function getFilterType($frontendInput) { $filtersMap = ['date' => 'dateRange']; $result = array_replace_recursive($this->dataTypeMap, $filtersMap); - return isset($result[$frontendInput]) ? $result[$frontendInput] : $result['default']; + return $result[$frontendInput] ?? $result['default']; } } diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php index d4dc9ddd7ca3b..dc3c94f384632 100644 --- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php +++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php @@ -74,6 +74,6 @@ public function prepareDataSource(array $dataSource) protected function getAlt($row) { $altField = $this->getData('config/altField') ?: self::ALT_FIELD; - return isset($row[$altField]) ? $row[$altField] : null; + return $row[$altField] ?? null; } } diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php index 019959f9c1fea..ecc4ff04ab8a7 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php @@ -26,15 +26,19 @@ public function __construct($entities) } /** + * Get + * * @param int $entityId * @return \Magento\Framework\DataObject|null */ public function get($entityId) { - return isset($this->entitiesMap[$entityId]) ? $this->entitiesMap[$entityId] : null; + return $this->entitiesMap[$entityId] ?? null; } /** + * List + * * @return \Magento\Framework\DataObject[] */ public function getList() diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php index 76c33f143e671..b9442797765c6 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php @@ -147,7 +147,7 @@ public function _beforeToHtml() */ public function getWebsiteCount($websiteId) { - return isset($this->_websiteCounts[$websiteId]) ? $this->_websiteCounts[$websiteId] : 0; + return $this->_websiteCounts[$websiteId] ?? 0; } /** @@ -166,13 +166,15 @@ public function getTotals() return $this->_collection->getTotals(); } - /** - * Format price by specified website - * - * @param float $price - * @param null|int $websiteId - * @return string - */ + /** + * Format price by specified website + * + * @param float $price + * @param null|int $websiteId + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function formatCurrency($price, $websiteId = null) { return $this->_storeManager->getWebsite($websiteId)->getBaseCurrency()->format($price); diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 6408276630c3f..2c0c7812ca669 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -230,7 +230,7 @@ public function getStreet() public function getStreetLine($number) { $lines = $this->getStreet(); - return isset($lines[$number - 1]) ? $lines[$number - 1] : ''; + return $lines[$number - 1] ?? ''; } /** diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index f6e63e04ac559..843867e183cac 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -982,11 +982,12 @@ public function getCode($type, $code = '') } } - /** - * Return FeDex currency ISO code by Magento Base Currency Code - * - * @return string 3-digit currency code - */ + /** + * Return FeDex currency ISO code by Magento Base Currency Code + * + * @return string 3-digit currency code + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrencyCode() { $codes = [ @@ -1008,7 +1009,7 @@ public function getCurrencyCode() ]; $currencyCode = $this->_storeManager->getStore()->getBaseCurrencyCode(); - return isset($codes[$currencyCode]) ? $codes[$currencyCode] : $currencyCode; + return $codes[$currencyCode] ?? $currencyCode; } /** diff --git a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php index cdca81ed98b7a..dbcb62907736c 100644 --- a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php +++ b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php @@ -72,6 +72,6 @@ public function create(VaultPaymentInterface $paymentMethod, int $storeId): Inte */ private function extractFromConfig($config, string $field, string $default): string { - return isset($config[$field]) ? $config[$field] : $default; + return $config[$field] ?? $default; } } diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index cdf7e0c6ac7c2..68090f12e99be 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -119,7 +119,7 @@ public function getName() */ public function getConfigData() { - return isset($this->data['config']) ? $this->data['config'] : []; + return $this->data['config'] ?? []; } /** diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index 77d8330a72550..eab671fdb85da 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -251,7 +251,7 @@ public function getStreet() public function getStreetLine($number) { $lines = $this->getStreet(); - return isset($lines[$number - 1]) ? $lines[$number - 1] : ''; + return $lines[$number - 1] ?? ''; } //@codeCoverageIgnoreStart diff --git a/app/code/Magento/Sales/Model/Order/Payment/Info.php b/app/code/Magento/Sales/Model/Order/Payment/Info.php index 063b3eaa71f1b..0a6b257846bfa 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Info.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Info.php @@ -181,7 +181,7 @@ public function getAdditionalInformation($key = null) if (null === $key) { return $this->additionalInformation; } - return isset($this->additionalInformation[$key]) ? $this->additionalInformation[$key] : null; + return $this->additionalInformation[$key] ?? null; } /** diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 8d8de47ba99cf..96312e7e0192b 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -472,7 +472,7 @@ public function getAdditionalInformation($key = null) $info = []; } if ($key) { - return isset($info[$key]) ? $info[$key] : null; + return $info[$key] ?? null; } return $info; } @@ -898,7 +898,7 @@ public function getTxnId() public function getHtmlTxnId() { $this->_eventManager->dispatch($this->_eventPrefix . '_html_txn_id', $this->_getEventData()); - return isset($this->_data['html_txn_id']) ? $this->_data['html_txn_id'] : $this->getTxnId(); + return $this->_data['html_txn_id'] ?? $this->getTxnId(); } /** diff --git a/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php b/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php index 87c5b917f6963..25c15449a9fb4 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php +++ b/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php @@ -103,6 +103,6 @@ protected function getLastUpdatedAtValue($default = '0000-00-00 00:00:00') $row = $this->getConnection()->fetchRow($select); - return isset($row['updated_at']) ? $row['updated_at'] : $default; + return $row['updated_at'] ?? $default; } } diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php index be2588dc48711..844258f80a284 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php @@ -184,11 +184,11 @@ public function setActiveFlag($code = 'active') /** * Return code of carrier * - * @return string + * @return string|null */ public function getCarrierCode() { - return isset($this->_code) ? $this->_code : null; + return $this->_code ?? null; } /** @@ -410,7 +410,7 @@ protected function _getCachedQuotes($requestParams) { $key = $this->_getQuotesCacheKey($requestParams); - return isset(self::$_quotesCache[$key]) ? self::$_quotesCache[$key] : null; + return self::$_quotesCache[$key] ?? null; } /** diff --git a/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php b/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php index f95968d4a1bf7..482f243f6f05d 100644 --- a/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php +++ b/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php @@ -41,6 +41,6 @@ private function getStreetLine($number, $street) { $lines = is_array($street) ? $street : []; - return isset($lines[$number - 1]) ? $lines[$number - 1] : ''; + return $lines[$number - 1] ?? ''; } } diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index af25957257421..47d89112c08ea 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -460,11 +460,12 @@ protected function _getSession() return $this->_session; } - /** - * Validation rules for store - * - * @return \Zend_Validate_Interface|null - */ + /** + * Validation rules for store + * + * @return \Zend_Validate_Interface|null + * @throws \Zend_Validate_Exception + */ protected function _getValidationRulesBeforeSave() { $validator = new \Magento\Framework\Validator\DataObject(); @@ -486,13 +487,15 @@ protected function _getValidationRulesBeforeSave() return $validator; } - /** - * Loading store data - * - * @param mixed $key - * @param string $field - * @return $this - */ + /** + * Loading store data + * + * @param mixed $key + * @param string $field + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function load($key, $field = null) { if (!is_numeric($key) && $field === null) { @@ -562,11 +565,12 @@ public function setWebsite(Website $website) $this->setWebsiteId($website->getId()); } - /** - * Retrieve store website - * - * @return Website|bool - */ + /** + * Retrieve store website + * + * @return Website|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getWebsite() { if ($this->getWebsiteId() === null) { @@ -575,13 +579,15 @@ public function getWebsite() return $this->websiteRepository->getById($this->getWebsiteId()); } - /** - * Retrieve url using store configuration specific - * - * @param string $route - * @param array $params - * @return string - */ + /** + * Retrieve url using store configuration specific + * + * @param string $route + * @param array $params + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getUrl($route = '', $params = []) { /** @var $url UrlInterface */ @@ -877,12 +883,14 @@ public function getDefaultCurrency() return $currency; } - /** - * Set current store currency code - * - * @param string $code - * @return string - */ + /** + * Set current store currency code + * + * @param string $code + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function setCurrentCurrencyCode($code) { $code = strtoupper($code); @@ -968,11 +976,12 @@ public function getAllowedCurrencies() return explode(',', $this->getConfig($this->_currencyInstalled)); } - /** - * Retrieve store current currency - * - * @return Currency - */ + /** + * Retrieve store current currency + * + * @return Currency + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrency() { $currency = $this->getData('current_currency'); @@ -990,21 +999,23 @@ public function getCurrentCurrency() return $currency; } - /** - * Retrieve current currency rate - * - * @return float - */ + /** + * Retrieve current currency rate + * + * @return float + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrencyRate() { return $this->getBaseCurrency()->getRate($this->getCurrentCurrency()); } - /** - * Retrieve root category identifier - * - * @return int - */ + /** + * Retrieve root category identifier + * + * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getRootCategoryId() { if (!$this->getGroup()) { @@ -1025,11 +1036,12 @@ public function setGroup(Group $group) return $this; } - /** - * Retrieve group model - * - * @return Group|bool - */ + /** + * Retrieve group model + * + * @return Group|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getGroup() { if (null === $this->getGroupId()) { @@ -1132,11 +1144,12 @@ public function getDefaultGroupId() return $this->_getData('default_group_id'); } - /** - * Check if store can be deleted - * - * @return boolean - */ + /** + * Check if store can be deleted + * + * @return boolean + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isCanDelete() { if (!$this->getId()) { @@ -1146,12 +1159,13 @@ public function isCanDelete() return $this->getGroup()->getStoresCount() > 1; } - /** - * Check if store is default - * - * @return boolean - * @since 100.1.0 - */ + /** + * Check if store is default + * + * @return boolean + * @since 100.1.0 + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isDefault() { if (!$this->getId() && $this->getWebsite() && $this->getWebsite()->getStoresCount() == 0) { @@ -1160,14 +1174,16 @@ public function isDefault() return $this->getGroup()->getDefaultStoreId() == $this->getId(); } - /** - * Retrieve current url for store - * - * @param bool $fromStore - * @return string - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ + /** + * Retrieve current url for store + * + * @param bool $fromStore + * + * @return string + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrentUrl($fromStore = true) { $sidQueryParam = $this->_sidResolver->getSessionIdQueryParam($this->_getSession()); @@ -1238,22 +1254,24 @@ public function isActive() return (bool)$this->_getData('is_active'); } - /** - * Protect delete from non admin area - * - * @return $this - */ + /** + * Protect delete from non admin area + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function beforeDelete() { $this->_configDataResource->clearScopeData(ScopeInterface::SCOPE_STORES, $this->getId()); return parent::beforeDelete(); } - /** - * Rewrite in order to clear configuration cache - * - * @return $this - */ + /** + * Rewrite in order to clear configuration cache + * + * @return $this + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function afterDelete() { $store = $this; @@ -1308,11 +1326,12 @@ public function isReadOnly($value = null) return $this->_isReadOnly; } - /** - * Retrieve store group name - * - * @return string - */ + /** + * Retrieve store group name + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getFrontendName() { if (null === $this->_frontendName) { @@ -1349,7 +1368,7 @@ public function getIdentities() public function getStorePath() { $parsedUrl = parse_url($this->getBaseUrl()); - return isset($parsedUrl['path']) ? $parsedUrl['path'] : '/'; + return $parsedUrl['path'] ?? '/'; } /** diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index d7e3bf94f548f..a951954600365 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -45,14 +45,16 @@ protected function _construct() $this->_init('layout_update', 'layout_update_id'); } - /** - * Retrieve layout updates by handle - * - * @param string $handle - * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface $store - * @return string - */ + /** + * Retrieve layout updates by handle + * + * @param string $handle + * @param \Magento\Framework\View\Design\ThemeInterface $theme + * @param \Magento\Framework\App\ScopeInterface $store + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function fetchUpdatesByHandle( $handle, \Magento\Framework\View\Design\ThemeInterface $theme, @@ -69,15 +71,17 @@ public function fetchUpdatesByHandle( $this->layoutUpdateCache[$cacheKey][$layout['handle']] .= $layout['xml']; } } - return isset($this->layoutUpdateCache[$cacheKey][$handle]) ? $this->layoutUpdateCache[$cacheKey][$handle] : ''; + return $this->layoutUpdateCache[$cacheKey][$handle] ?? ''; } - /** - * Get select to fetch updates by handle - * - * @param bool $loadAllUpdates - * @return \Magento\Framework\DB\Select - */ + /** + * Get select to fetch updates by handle + * + * @param bool $loadAllUpdates + * + * @return \Magento\Framework\DB\Select + * @throws \Magento\Framework\Exception\LocalizedException + */ protected function _getFetchUpdatesByHandleSelect($loadAllUpdates = false) { //@todo Why it also loads layout updates for store_id=0, isn't it Admin Store View? From b48171bfa9c5fdb5ce1101dff67b4e3e0e5189ff Mon Sep 17 00:00:00 2001 From: Aleksey Tsoy <aleksey_tsoy@epam.com> Date: Wed, 19 Sep 2018 13:48:06 +0600 Subject: [PATCH 0058/1158] MAGETWO-71022: After return is complete in Admin, 'remaining quantity' in customer account shows incorrect value - Added automated test --- .../Mftf/ActionGroup/AdminInvoiceActionGroup.xml | 12 ++++++++++++ .../Mftf/ActionGroup/AdminShipmentActionGroup.xml | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml index 15aff7c751a11..905cb08a401e1 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml @@ -38,4 +38,16 @@ </arguments> <see selector="{{AdminInvoiceItemsSection.skuColumn}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> </actionGroup> + + <actionGroup name="goToInvoiceIntoOrder"> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceAction"/> + <seeInCurrentUrl url="{{AdminInvoiceNewPage.url}}" stepKey="seeOrderInvoiceUrl"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage"/> + </actionGroup> + + <actionGroup name="submitInvoiceIntoOrder"> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPageInvoice"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml index 85430aeaa4168..3d70a742b13eb 100644 --- a/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml +++ b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml @@ -35,4 +35,16 @@ </arguments> <see selector="{{AdminShipmentItemsSection.skuColumn}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> </actionGroup> + + <actionGroup name="goToShipmentIntoOrder"> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> + <seeInCurrentUrl url="{{AdminShipmentNewPage.url}}" stepKey="seeOrderShipmentUrl"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Shipment" stepKey="seePageNameNewInvoicePage"/> + </actionGroup> + + <actionGroup name="submitShipmentIntoOrder"> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPageShipping"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="seeShipmentCreateSuccess"/> + </actionGroup> </actionGroups> \ No newline at end of file From 78327c1ab246fc20ed84ee54ed67e2d97a1c5131 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Wed, 19 Sep 2018 14:06:15 +0300 Subject: [PATCH 0059/1158] MAGETWO-91657: Advanced pricing the bulk discounts by percentage returns error when set - Added validation for discount value field in Advanced Pricing section of product. --- .../Ui/DataProvider/Product/Form/Modifier/TierPrice.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php index 0eddca3322205..5f8d7fcf9049a 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php @@ -45,7 +45,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @since 101.1.0 */ public function modifyData(array $data) @@ -54,8 +54,11 @@ public function modifyData(array $data) } /** - * {@inheritdoc} + * Add tier price info to meta array. {@inheritdoc} + * * @since 101.1.0 + * @param array $meta + * @return array */ public function modifyMeta(array $meta) { @@ -150,7 +153,9 @@ private function getUpdatedTierPriceStructure(array $priceMeta) 'dataType' => Price::NAME, 'addbefore' => '%', 'validation' => [ + 'required-entry' => true, 'validate-number' => true, + 'validate-greater-than-zero' => true, 'less-than-equals-to' => 100 ], 'visible' => $firstOption From f017676c873418b4e87b306e8666f9db39e82b99 Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Wed, 19 Sep 2018 15:45:48 +0400 Subject: [PATCH 0060/1158] MAGETWO-91617: Ordered Products Report Error for restricted scope admin - Add fixed code --- .../ActionGroup/AdminOrderActionGroup.xml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index ffa6a2a5f2d99..aa6c10400d48b 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -259,16 +259,6 @@ <see selector="{{AdminOrderItemsOrderedSection.productSkuColumn}}" userInput="{{product.sku}}" stepKey="seeSkuInItemsOrdered"/> </actionGroup> - <!--Cancel order that is in pending status--> - <actionGroup name="cancelPendingOrder"> - <click selector="{{AdminOrderDetailsMainActionsSection.cancel}}" stepKey="clickCancelOrder"/> - <waitForElement selector="{{AdminConfirmationModalSection.message}}" stepKey="waitForCancelConfirmation"/> - <see selector="{{AdminConfirmationModalSection.message}}" userInput="Are you sure you want to cancel this order?" stepKey="seeConfirmationMessage"/> - <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmOrderCancel"/> - <see selector="{{AdminMessagesSection.success}}" userInput="You canceled the order." stepKey="seeCancelSuccessMessage"/> - <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Canceled" stepKey="seeOrderStatusCanceled"/> - </actionGroup> - <actionGroup name="CreateOrderInStoreActionGroup"> <arguments> <argument name="product"/> @@ -292,4 +282,14 @@ <click selector="{{OrdersGridSection.submitOrder}}" stepKey="submitOrder"/> <see stepKey="seeSuccessMessageForOrder" userInput="You created the order."/> </actionGroup> + + <!--Cancel order that is in pending status--> + <actionGroup name="cancelPendingOrder"> + <click selector="{{AdminOrderDetailsMainActionsSection.cancel}}" stepKey="clickCancelOrder"/> + <waitForElement selector="{{AdminConfirmationModalSection.message}}" stepKey="waitForCancelConfirmation"/> + <see selector="{{AdminConfirmationModalSection.message}}" userInput="Are you sure you want to cancel this order?" stepKey="seeConfirmationMessage"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmOrderCancel"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You canceled the order." stepKey="seeCancelSuccessMessage"/> + <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Canceled" stepKey="seeOrderStatusCanceled"/> + </actionGroup> </actionGroups> From 5333ca582fcc97c6926df798c96eba3378b7c3e2 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Wed, 19 Sep 2018 15:13:26 +0300 Subject: [PATCH 0061/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fixed statics. --- .../Test/Unit/Block/Product/ProductList/ToolbarTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php index 8282ffa409f9c..884f4c543c8b8 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php @@ -67,13 +67,16 @@ protected function setUp() 'getLimit', 'getCurrentPage' ]); - $this->memorizer = $this->createPartialMock(\Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer::class, [ + $this->memorizer = $this->createPartialMock( + \Magento\Catalog\Model\Product\ProductList\ToolbarMemorizer::class, + [ 'getDirection', 'getOrder', 'getMode', 'getLimit', 'isMemorizingAllowed' - ]); + ] + ); $this->layout = $this->createPartialMock(\Magento\Framework\View\Layout::class, ['getChildName', 'getBlock']); $this->pagerBlock = $this->createPartialMock(\Magento\Theme\Block\Html\Pager::class, [ 'setUseContainer', From 949aa6b9ae92153fa7cd0d0453742259c33ee54c Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Wed, 19 Sep 2018 16:17:22 +0300 Subject: [PATCH 0062/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Fixes according to code review. --- app/code/Magento/GiftMessage/Block/Message/Inline.php | 7 ++----- .../GiftMessage/view/frontend/templates/inline.phtml | 8 +++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/GiftMessage/Block/Message/Inline.php b/app/code/Magento/GiftMessage/Block/Message/Inline.php index 1a874cb5ea4ae..f44f967cefdc6 100644 --- a/app/code/Magento/GiftMessage/Block/Message/Inline.php +++ b/app/code/Magento/GiftMessage/Block/Message/Inline.php @@ -330,14 +330,11 @@ public function getEscaped($value, $defaultValue = '') * * @return bool */ - public function isOrderLevelAvailable() + public function isMessagesOrderAvailable() { $entity = $this->getEntity(); if (!$entity->hasIsGiftOptionsAvailable()) { $this->_eventManager->dispatch('gift_options_prepare', ['entity' => $entity]); - if (!$entity->getIsGiftOptionsAvailable()) { - $entity->setIsGiftOptionsAvailable($this->isMessagesAvailable()); - } } return $entity->getIsGiftOptionsAvailable(); } @@ -372,7 +369,7 @@ public function isItemMessagesAvailable($item) protected function _toHtml() { // render HTML when messages are allowed for order or for items only - if ($this->isItemsAvailable() || $this->isOrderLevelAvailable()) { + if ($this->isItemsAvailable() || $this->isMessagesAvailable() || $this->isMessagesOrderAvailable()) { return parent::_toHtml(); } return ''; diff --git a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml index 8c58959be15b7..640ef1ba16486 100644 --- a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml +++ b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml @@ -18,7 +18,7 @@ </div> <dl class="options-items" id="allow-gift-options-container"> - <?php if ($block->isOrderLevelAvailable()): ?> + <?php if ($block->isMessagesAvailable()): ?> <dt id="add-gift-options-for-order-<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>" class="order-title"> <div class="field choice"> <input type="checkbox" name="allow_gift_messages_for_order" id="allow_gift_options_for_order" data-mage-init='{"giftOptions":{}}' value="1" data-selector='{"id":"#allow-gift-options-for-order-container"}'<?php if ($block->getEntityHasMessage()): ?> checked="checked"<?php endif; ?> class="checkbox" /> @@ -28,7 +28,6 @@ <dd id="allow-gift-options-for-order-container" class="order-options"> <div class="options-order-container" id="options-order-container-<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>"></div> - <?php if ($block->isMessagesAvailable()): ?> <button class="action action-gift" data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#allow-gift-messages-for-order-container"}}'> <span><?= /* @escapeNotVerified */ __('Gift Message') ?></span> @@ -63,9 +62,8 @@ }); </script> </div> - <?php endif; ?> </dd> - <?php endif; ?> + <?php endif ?> <?php if ($block->isItemsAvailable()): ?> <dt id="add-gift-options-for-items-<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>" class="order-title individual"> <div class="field choice"> @@ -154,7 +152,7 @@ </div> <dl class="options-items" id="allow-gift-options-container-<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>"> - <?php if ($block->isOrderLevelAvailable()): ?> + <?php if ($block->isMessagesOrderAvailable() || $block->isMessagesAvailable()): ?> <dt id="add-gift-options-for-order-<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>" class="order-title"> <div class="field choice"> <input type="checkbox" name="allow_gift_options_for_order_<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>" id="allow_gift_options_for_order_<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>" data-mage-init='{"giftOptions":{}}' value="1" data-selector='{"id":"#allow-gift-options-for-order-container-<?= /* @escapeNotVerified */ $block->getEntity()->getId() ?>"}'<?php if ($block->getEntityHasMessage()): ?> checked="checked"<?php endif; ?> class="checkbox" /> From 2f3d3f65c16453df6d7d8bf372fa10032d7866fd Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Wed, 19 Sep 2018 16:43:18 +0300 Subject: [PATCH 0063/1158] MAGETWO-91785: Fixed incorrect order returns request flow --- .../Sales/Controller/AbstractController/Reorder.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index a96892978c7fb..a03456d4c1f5f 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -7,15 +7,15 @@ namespace Magento\Sales\Controller\AbstractController; use Magento\Framework\App\Action; -use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Registry; +use Magento\Framework\App\Action\HttpPostActionInterface; /** * Class Reorder * * @package Magento\Sales\Controller\AbstractController */ -abstract class Reorder extends Action\Action +abstract class Reorder extends Action\Action implements HttpPostActionInterface { /** * @var \Magento\Sales\Controller\AbstractController\OrderLoaderInterface @@ -50,10 +50,6 @@ public function __construct( */ public function execute() { - if (!$this->getRequest()->isPost()) { - throw new NotFoundException(__('Page not Found')); - } - $result = $this->orderLoader->load($this->_request); if ($result instanceof \Magento\Framework\Controller\ResultInterface) { return $result; From 9302a4f3f22217c6a71002ce009ba3d8ae4897b4 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Wed, 19 Sep 2018 15:45:28 +0200 Subject: [PATCH 0064/1158] Increased limiter values for passing the tests --- app/code/Magento/GraphQl/etc/di.xml | 4 +- .../Framework/QueryComplexityLimiterTest.php | 133 +++++++++++++++++- .../GraphQl/Query/QueryComplexityLimiter.php | 4 +- 3 files changed, 134 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index b1d24ce6c4a55..622888f697b84 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -99,8 +99,8 @@ </type> <type name="Magento\Framework\GraphQl\Query\QueryComplexityLimiter"> <arguments> - <argument name="queryDepth" xsi:type="number">15</argument> - <argument name="queryComplexity" xsi:type="number">50</argument> + <argument name="queryDepth" xsi:type="number">20</argument> + <argument name="queryComplexity" xsi:type="number">160</argument> </arguments> </type> </config> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php index 4616c450786ed..3304d9e6198f4 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -90,6 +90,127 @@ public function testQueryComplexityIsLimited() id types } + categories { + id + position + level + url_key + url_path + product_count + breadcrumbs { + category_id + category_name + category_url_key + } + products { + items { + name + special_from_date + special_to_date + new_to_date + new_from_date + tier_price + manufacturer + thumbnail + sku + image + canonical_url + updated_at + created_at + categories { + id + position + level + url_key + url_path + product_count + breadcrumbs { + category_id + category_name + category_url_key + } + products { + items { + name + special_from_date + special_to_date + new_to_date + new_from_date + tier_price + manufacturer + sku + image + canonical_url + updated_at + created_at + categories { + id + position + level + url_key + url_path + product_count + breadcrumbs { + category_id + category_name + category_url_key + } + products { + items { + name + special_from_date + special_to_date + new_to_date + new_from_date + tier_price + manufacturer + sku + image + thumbnail + canonical_url + updated_at + created_at + categories { + id + position + position + position + position + position + position + position + position + position + position + position + position + position + position + position + position + position + position + position + level + url_key + url_path + product_count + default_sort_by + breadcrumbs { + category_id + category_name + category_url_key + } + } + } + } + } + } + } + } + } + } + } } } } @@ -102,7 +223,7 @@ public function testQueryComplexityIsLimited() } QUERY; - self::expectExceptionMessageRegExp('/Max query complexity should be 50 but got 62/'); + self::expectExceptionMessageRegExp('/Max query complexity should be 160 but got 169/'); $this->graphQlQuery($query); } @@ -139,7 +260,13 @@ public function testQueryDepthIsLimited() categories { products { items { - name + categories { + products { + items { + name + } + } + } } } } @@ -163,7 +290,7 @@ public function testQueryDepthIsLimited() } } QUERY; - self::expectExceptionMessageRegExp('/Max query depth should be 15 but got 20/'); + self::expectExceptionMessageRegExp('/Max query depth should be 20 but got 23/'); $this->graphQlQuery($query); } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index b302f4272527a..3936da21fc56a 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -38,8 +38,8 @@ class QueryComplexityLimiter * @param int $queryComplexity */ public function __construct( - int $queryDepth = 15, - int $queryComplexity = 50 + int $queryDepth = 20, + int $queryComplexity = 160 ) { $this->queryDepth = $queryDepth; $this->queryComplexity = $queryComplexity; From cfcde56d19116889ef6e20f4e56e5b2a250674ec Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Wed, 19 Sep 2018 16:45:48 +0300 Subject: [PATCH 0065/1158] MAGETWO-91785: Fixed incorrect order returns request flow --- app/code/Magento/Sales/Controller/AbstractController/Reorder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index a03456d4c1f5f..2cd031c9f1f6e 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -46,7 +46,6 @@ public function __construct( * Action for reorder * * @return \Magento\Framework\Controller\ResultInterface - * @throws NotFoundException */ public function execute() { From 8024b4c1c2a5c3a28c42805c3d52edea536f7501 Mon Sep 17 00:00:00 2001 From: "Hakobyan, Lusine" <Lusine_Hakobyan@epam.com> Date: Thu, 20 Sep 2018 11:24:47 +0400 Subject: [PATCH 0066/1158] MAGETWO-91704: Can't cancel/change payment method after chosen Store Credit - Update automated test according to review --- .../Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml index 8aaf626edab33..24ff30071830f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml @@ -9,7 +9,6 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderFormPaymentSection"> - <element name="useCustomerBalance" type="checkbox" selector="#p_method_use_customerbalance"/> <element name="header" type="text" selector="#order-methods span.title"/> <element name="getShippingMethods" type="text" selector="#order-shipping_method a.action-default" timeout="30"/> <element name="flatRateOption" type="radio" selector="#s_method_flatrate_flatrate" timeout="30"/> From a43f6603f2114ddaaebc5e76616d0c315e86203b Mon Sep 17 00:00:00 2001 From: vprohorov <prohorov.vital@gmail.com> Date: Wed, 19 Sep 2018 02:50:20 +0300 Subject: [PATCH 0067/1158] MAGETWO-91537: Search synonyms results missing for words including hyphen and numbers - Removing hyphen from SPECIAL_CHARACTERS constant --- .../Search/Adapter/Mysql/Query/Builder/Match.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php index 8e3758817adf0..28e321d4c5d47 100644 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php +++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php @@ -15,11 +15,16 @@ use Magento\Framework\Search\Adapter\Preprocessor\PreprocessorInterface; /** + * Class for building select where condition. + * * @api */ class Match implements QueryInterface { - const SPECIAL_CHARACTERS = '-+~/\\<>\'":*$#@()!,.?`=%&^'; + /** + * @var string + */ + const SPECIAL_CHARACTERS = '+~/\\<>\'":*$#@()!,.?`=%&^'; const MINIMAL_CHARACTER_LENGTH = 3; @@ -69,7 +74,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function build( ScoreBuilder $scoreBuilder, @@ -113,6 +118,8 @@ public function build( } /** + * Prepare query value for build function. + * * @param string $queryValue * @param string $conditionType * @return string From 6e20bdd2d7e4bc3b177980620eac2161281f10ae Mon Sep 17 00:00:00 2001 From: Aleksey Tsoy <aleksey_tsoy@epam.com> Date: Thu, 20 Sep 2018 16:55:49 +0600 Subject: [PATCH 0068/1158] MAGETWO-91658: Wrong Checkout Totals Sort Order in cart - Added automated test --- .../Mftf/ActionGroup/CheckoutActionGroup.xml | 8 ++ .../Test/Mftf/Data/CheckoutConfigData.xml | 25 ++++++ .../Mftf/Metadata/checkout_config-meta.xml | 86 +++++++++++++++++++ .../Section/CheckoutCartSummarySection.xml | 1 + .../CheckoutTotalsSortOrderInCartTest.xml | 53 ++++++++++++ .../Test/Mftf/Data/SalesRuleData.xml | 29 +++++++ 6 files changed, 202 insertions(+) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml create mode 100644 app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index 41be15d0ca410..01a7d8ead9132 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -86,6 +86,14 @@ <see userInput="${{total}}" selector="{{CheckoutPaymentSection.orderSummaryTotal}}" stepKey="assertTotal"/> </actionGroup> + <actionGroup name="CheckTotalsSortOrderInSummarySection"> + <arguments> + <argument name="elementName" type="string"/> + <argument name="positionNumber" type="integer"/> + </arguments> + <see userInput="{{elementName}}" selector="{{CheckoutCartSummarySection.elementPosition(positionNumber)}}" stepKey="assertElementPosition"/> + </actionGroup> + <!-- Check ship to information in checkout --> <actionGroup name="CheckShipToInformationInCheckoutActionGroup"> <arguments> diff --git a/app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml b/app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml new file mode 100644 index 0000000000000..bf2ae28009011 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="CheckoutShippingTotalsSortOrder" type="checkout_totals_sort_order"> + <requiredEntity type="shipping">ShippingTotalsSortOrder</requiredEntity> + </entity> + + <entity name="ShippingTotalsSortOrder" type="shipping"> + <data key="value">27</data> + </entity> + + <entity name="DefaultCheckoutTotalsSortOrder" type="default_checkout_totals_sort_order"> + <requiredEntity type="checkoutTotalFlagZero">DefaultTotalFlagZero</requiredEntity> + </entity> + <entity name="DefaultTotalFlagZero" type="checkoutTotalFlagZero"> + <data key="value">0</data> + </entity> +</entities> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml b/app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml new file mode 100644 index 0000000000000..55572ee73ac46 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="SetCheckoutTotalsSortOrder" dataType="checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST"> + <object key="groups" dataType="checkout_totals_sort_order"> + <object key="totals_sort" dataType="checkout_totals_sort_order"> + <object key="fields" dataType="checkout_totals_sort_order"> + <object key="subtotal" dataType="subtotal"> + <field key="value">integer</field> + </object> + <object key="discount" dataType="discount"> + <field key="value">integer</field> + </object> + <object key="shipping" dataType="shipping"> + <field key="value">integer</field> + </object> + <object key="tax" dataType="tax"> + <field key="value">integer</field> + </object> + <object key="weee" dataType="weee"> + <field key="value">integer</field> + </object> + <object key="grand_total" dataType="grand_total"> + <field key="value">integer</field> + </object> + <object key="giftcardaccount" dataType="giftcardaccount"> + <field key="value">integer</field> + </object> + <object key="customerbalance" dataType="customerbalance"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </operation> + + <operation name="DefaultCheckoutTotalsSortOrder" dataType="default_checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST"> + <object key="groups" dataType="default_checkout_totals_sort_order"> + <object key="totals_sort" dataType="default_checkout_totals_sort_order"> + <object key="fields" dataType="default_checkout_totals_sort_order"> + <object key="subtotal" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="discount" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="shipping" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="tax" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="weee" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="grand_total" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="giftcardaccount" dataType="giftcardaccount"> + <field key="value">integer</field> + </object> + <object key="customerbalance" dataType="customerbalance"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </operation> +</operations> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml index a1a8d2ba3eade..b1547f2ef4d92 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml @@ -9,6 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="CheckoutCartSummarySection"> + <element name="elementPosition" type="text" selector=".data.table.totals > tbody tr:nth-of-type({{value}}) > th" parameterized="true"/> <element name="subtotal" type="text" selector="//*[@id='cart-totals']//tr[@class='totals sub']//td//span[@class='price']"/> <element name="shippingMethod" type="text" selector="//*[@id='cart-totals']//tr[@class='totals shipping excl']//th//span[@class='value']"/> <element name="shipping" type="text" selector="//*[@id='cart-totals']//tr[@class='totals shipping excl']//td//span[@class='price']"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml new file mode 100644 index 0000000000000..e1ec9032e072a --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="CheckoutTotalsSortOrderInCartTest"> + <annotations> + <title value="Checkout Totals Sort Order configuration and displaying in cart"/> + <stories value="MAGETWO-91658: Wrong Checkout Totals Sort Order in cart"/> + <description value="Checkout Totals Sort Order configuration and displaying in cart"/> + <features value="Checkout"/> + <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-94944"/> + <group value="Checkout"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="defaultCategory"/> + <createData entity="SimpleProduct" stepKey="simpleProduct"> + <requiredEntity createDataKey="defaultCategory"/> + </createData> + + <createData entity="ApiCartRule" stepKey="cartRule"/> + + <createData entity="CheckoutShippingTotalsSortOrder" stepKey="setConfigShippingTotalsSortOrder"/> + </before> + + <actionGroup ref="VerifyDiscountAmount" stepKey="verifyStorefront"> + <argument name="productUrl" value="$$simpleProduct.sku$$.html"/> + <argument name="quantity" value="1"/> + <argument name="expectedDiscount" value="-$61.50"/> + </actionGroup> + + <actionGroup ref="CheckTotalsSortOrderInSummarySection" stepKey="checkTotalsSortOrderInSummarySection"> + <argument name="elementName" value="Shipping (Flat Rate - Fixed)"/> + <argument name="positionNumber" value="3"/> + </actionGroup> + + <after> + <createData entity="DefaultCheckoutTotalsSortOrder" stepKey="setDefaultTotalsSortOrder"/> + + <deleteData createDataKey="cartRule" stepKey="deleteCartRule"/> + <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="defaultCategory" stepKey="deleteCategory"/> + + <magentoCLI command="cache:flush" stepKey="flushCache"/> + </after> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml index 5b7585b8b2a3f..2ac4917683450 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml @@ -39,6 +39,35 @@ <requiredEntity type="SalesRuleLabel">SalesRuleLabelStore1</requiredEntity> </entity> + <entity name="ApiCartRule" type="SalesRule"> + <data key="name" unique="suffix">salesRule</data> + <data key="description">Sales Rule Descritpion</data> + <array key="website_ids"> + <item>1</item> + </array> + <array key="customer_group_ids"> + <item>0</item> + <item>1</item> + <item>3</item> + </array> + <data key="uses_per_customer">0</data> + <data key="is_active">true</data> + <data key="stop_rules_processing">true</data> + <data key="is_advanced">true</data> + <data key="sort_order">0</data> + <data key="simple_action">by_percent</data> + <data key="discount_amount">50</data> + <data key="discount_qty">0</data> + <data key="discount_step">0</data> + <data key="apply_to_shipping">false</data> + <data key="times_used">0</data> + <data key="is_rss">true</data> + <data key="coupon_type">NO_COUPON</data> + <data key="use_auto_generation">false</data> + <data key="uses_per_coupon">0</data> + <data key="simple_free_shipping">0</data> + </entity> + <entity name="SimpleSalesRule" type="SalesRule"> <data key="name" unique="suffix">SimpleSalesRule</data> <data key="is_active">true</data> From 10c08ae5c26307668964bf03ad7ef124ffddde5a Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Thu, 20 Sep 2018 19:36:02 +0300 Subject: [PATCH 0069/1158] MAGETWO-91733: Unusual behavior with the persistent shopping cart after the session is expired - Added observer to pass customer data from persistent session to checkout session --- ...tCheckoutSessionPersistentDataObserver.php | 90 +++++++++++ .../SetLoadPersistentQuoteObserver.php | 78 --------- ...ckoutSessionPersistentDataObserverTest.php | 149 ++++++++++++++++++ .../SetLoadPersistentQuoteObserverTest.php | 73 --------- .../Persistent/etc/frontend/events.xml | 2 +- .../Persistent/etc/webapi_rest/events.xml | 2 +- .../Persistent/etc/webapi_soap/events.xml | 2 +- 7 files changed, 242 insertions(+), 154 deletions(-) create mode 100644 app/code/Magento/Persistent/Observer/SetCheckoutSessionPersistentDataObserver.php delete mode 100644 app/code/Magento/Persistent/Observer/SetLoadPersistentQuoteObserver.php create mode 100644 app/code/Magento/Persistent/Test/Unit/Observer/SetCheckoutSessionPersistentDataObserverTest.php delete mode 100644 app/code/Magento/Persistent/Test/Unit/Observer/SetLoadPersistentQuoteObserverTest.php diff --git a/app/code/Magento/Persistent/Observer/SetCheckoutSessionPersistentDataObserver.php b/app/code/Magento/Persistent/Observer/SetCheckoutSessionPersistentDataObserver.php new file mode 100644 index 0000000000000..e89a09c0d2a9c --- /dev/null +++ b/app/code/Magento/Persistent/Observer/SetCheckoutSessionPersistentDataObserver.php @@ -0,0 +1,90 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Persistent\Observer; + +use Magento\Framework\Event\ObserverInterface; + +/** + * Class SetCheckoutSessionPersistentDataObserver + */ +class SetCheckoutSessionPersistentDataObserver implements ObserverInterface +{ + /** + * Persistent session + * + * @var \Magento\Persistent\Helper\Session + */ + private $persistentSession = null; + + /** + * Customer session + * + * @var \Magento\Customer\Model\Session + */ + private $customerSession; + + /** + * Persistent data + * + * @var \Magento\Persistent\Helper\Data + */ + private $persistentData = null; + + /** + * Customer Repository + * + * @var \Magento\Customer\Api\CustomerRepositoryInterface + */ + private $customerRepository = null; + + /** + * @param \Magento\Persistent\Helper\Session $persistentSession + * @param \Magento\Customer\Model\Session $customerSession + * @param \Magento\Persistent\Helper\Data $persistentData + * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository + */ + public function __construct( + \Magento\Persistent\Helper\Session $persistentSession, + \Magento\Customer\Model\Session $customerSession, + \Magento\Persistent\Helper\Data $persistentData, + \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository + ) { + $this->persistentSession = $persistentSession; + $this->customerSession = $customerSession; + $this->persistentData = $persistentData; + $this->customerRepository = $customerRepository; + } + + /** + * Pass customer data from persistent session to checkout session and set quote to be loaded even if not active + * + * @param \Magento\Framework\Event\Observer $observer + * @return void + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function execute(\Magento\Framework\Event\Observer $observer) + { + /** @var $checkoutSession \Magento\Checkout\Model\Session */ + $checkoutSession = $observer->getEvent()->getData('checkout_session'); + if ($this->persistentData->isShoppingCartPersist() && $this->persistentSession->isPersistent()) { + $checkoutSession->setCustomerData( + $this->customerRepository->getById($this->persistentSession->getSession()->getCustomerId()) + ); + } + if (!(($this->persistentSession->isPersistent() && !$this->customerSession->isLoggedIn()) + && !$this->persistentData->isShoppingCartPersist() + )) { + return; + } + if ($checkoutSession) { + $checkoutSession->setLoadInactive(); + } + } +} diff --git a/app/code/Magento/Persistent/Observer/SetLoadPersistentQuoteObserver.php b/app/code/Magento/Persistent/Observer/SetLoadPersistentQuoteObserver.php deleted file mode 100644 index 6eeab94a91cca..0000000000000 --- a/app/code/Magento/Persistent/Observer/SetLoadPersistentQuoteObserver.php +++ /dev/null @@ -1,78 +0,0 @@ -<?php -/** - * - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Persistent\Observer; - -use Magento\Framework\Event\ObserverInterface; - -class SetLoadPersistentQuoteObserver implements ObserverInterface -{ - /** - * Customer session - * - * @var \Magento\Customer\Model\Session - */ - protected $_customerSession; - - /** - * Checkout session - * - * @var \Magento\Checkout\Model\Session - */ - protected $_checkoutSession; - - /** - * Persistent session - * - * @var \Magento\Persistent\Helper\Session - */ - protected $_persistentSession = null; - - /** - * Persistent data - * - * @var \Magento\Persistent\Helper\Data - */ - protected $_persistentData = null; - - /** - * @param \Magento\Persistent\Helper\Session $persistentSession - * @param \Magento\Persistent\Helper\Data $persistentData - * @param \Magento\Customer\Model\Session $customerSession - * @param \Magento\Checkout\Model\Session $checkoutSession - */ - public function __construct( - \Magento\Persistent\Helper\Session $persistentSession, - \Magento\Persistent\Helper\Data $persistentData, - \Magento\Customer\Model\Session $customerSession, - \Magento\Checkout\Model\Session $checkoutSession - ) { - $this->_persistentSession = $persistentSession; - $this->_customerSession = $customerSession; - $this->_checkoutSession = $checkoutSession; - $this->_persistentData = $persistentData; - } - - /** - * Set quote to be loaded even if not active - * - * @param \Magento\Framework\Event\Observer $observer - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function execute(\Magento\Framework\Event\Observer $observer) - { - if (!(($this->_persistentSession->isPersistent() && !$this->_customerSession->isLoggedIn()) - && !$this->_persistentData->isShoppingCartPersist() - )) { - return; - } - - if ($this->_checkoutSession) { - $this->_checkoutSession->setLoadInactive(); - } - } -} diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/SetCheckoutSessionPersistentDataObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/SetCheckoutSessionPersistentDataObserverTest.php new file mode 100644 index 0000000000000..01c217c1c5cd4 --- /dev/null +++ b/app/code/Magento/Persistent/Test/Unit/Observer/SetCheckoutSessionPersistentDataObserverTest.php @@ -0,0 +1,149 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Persistent\Test\Unit\Observer; + +/** + * Class SetCheckoutSessionPersistentDataObserverTest + */ +class SetCheckoutSessionPersistentDataObserverTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Persistent\Observer\SetCheckoutSessionPersistentDataObserver + */ + private $model; + + /** + * @var \Magento\Persistent\Helper\Data| \PHPUnit_Framework_MockObject_MockObject + */ + private $helperMock; + + /** + * @var \Magento\Persistent\Helper\Session| \PHPUnit_Framework_MockObject_MockObject + */ + private $sessionHelperMock; + + /** + * @var \Magento\Checkout\Model\Session| \PHPUnit_Framework_MockObject_MockObject + */ + private $checkoutSessionMock; + + /** + * @var \Magento\Customer\Model\Session| \PHPUnit_Framework_MockObject_MockObject + */ + private $customerSessionMock; + + /** + * @var \Magento\Persistent\Model\Session| \PHPUnit_Framework_MockObject_MockObject + */ + private $persistentSessionMock; + + /** + * @var \Magento\Customer\Api\CustomerRepositoryInterface| \PHPUnit_Framework_MockObject_MockObject + */ + private $customerRepositoryMock; + + /** + * @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject + */ + private $observerMock; + + /** + * @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject + */ + private $eventMock; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->helperMock = $this->createMock(\Magento\Persistent\Helper\Data::class); + $this->sessionHelperMock = $this->createMock(\Magento\Persistent\Helper\Session::class); + $this->checkoutSessionMock = $this->createMock(\Magento\Checkout\Model\Session::class); + $this->customerSessionMock = $this->createMock(\Magento\Customer\Model\Session::class); + $this->observerMock = $this->createMock(\Magento\Framework\Event\Observer::class); + $this->eventMock = $this->createPartialMock(\Magento\Framework\Event::class, ['getData']); + $this->persistentSessionMock = $this->createPartialMock( + \Magento\Persistent\Model\Session::class, + ['getCustomerId'] + ); + $this->customerRepositoryMock = $this->createMock( + \Magento\Customer\Api\CustomerRepositoryInterface::class + ); + $this->model = new \Magento\Persistent\Observer\SetCheckoutSessionPersistentDataObserver( + $this->sessionHelperMock, + $this->customerSessionMock, + $this->helperMock, + $this->customerRepositoryMock + ); + } + + /** + * Test execute method when session is not persistent + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testExecuteWhenSessionIsNotPersistent() + { + $this->observerMock->expects($this->once()) + ->method('getEvent') + ->will($this->returnValue($this->eventMock)); + $this->eventMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue($this->checkoutSessionMock)); + $this->sessionHelperMock->expects($this->once()) + ->method('isPersistent') + ->will($this->returnValue(false)); + $this->checkoutSessionMock->expects($this->never()) + ->method('setLoadInactive'); + $this->checkoutSessionMock->expects($this->never()) + ->method('setCustomerData'); + $this->model->execute($this->observerMock); + } + + /** + * Test execute method when session is persistent + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testExecute() + { + $this->observerMock->expects($this->once()) + ->method('getEvent') + ->will($this->returnValue($this->eventMock)); + $this->eventMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue($this->checkoutSessionMock)); + $this->sessionHelperMock->expects($this->exactly(2)) + ->method('isPersistent') + ->will($this->returnValue(true)); + $this->customerSessionMock->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(false)); + $this->helperMock->expects($this->exactly(2)) + ->method('isShoppingCartPersist') + ->will($this->returnValue(true)); + $this->persistentSessionMock->expects($this->once()) + ->method('getCustomerId') + ->will($this->returnValue(123)); + $this->sessionHelperMock->expects($this->once()) + ->method('getSession') + ->will($this->returnValue($this->persistentSessionMock)); + $this->customerRepositoryMock->expects($this->once()) + ->method('getById') + ->will($this->returnValue(true)); //? + $this->checkoutSessionMock->expects($this->never()) + ->method('setLoadInactive'); + $this->checkoutSessionMock->expects($this->once()) + ->method('setCustomerData'); + $this->model->execute($this->observerMock); + } +} diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/SetLoadPersistentQuoteObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/SetLoadPersistentQuoteObserverTest.php deleted file mode 100644 index fd78a6852ea59..0000000000000 --- a/app/code/Magento/Persistent/Test/Unit/Observer/SetLoadPersistentQuoteObserverTest.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/** - * - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Persistent\Test\Unit\Observer; - -class SetLoadPersistentQuoteObserverTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Persistent\Observer\SetLoadPersistentQuoteObserver - */ - protected $model; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $helperMock; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $sessionHelperMock; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $checkoutSessionMock; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $customerSessionMock; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $observerMock; - - protected function setUp() - { - $this->helperMock = $this->createMock(\Magento\Persistent\Helper\Data::class); - $this->sessionHelperMock = $this->createMock(\Magento\Persistent\Helper\Session::class); - $this->checkoutSessionMock = $this->createMock(\Magento\Checkout\Model\Session::class); - $this->customerSessionMock = $this->createMock(\Magento\Customer\Model\Session::class); - $this->observerMock = $this->createMock(\Magento\Framework\Event\Observer::class); - - $this->model = new \Magento\Persistent\Observer\SetLoadPersistentQuoteObserver( - $this->sessionHelperMock, - $this->helperMock, - $this->customerSessionMock, - $this->checkoutSessionMock - ); - } - - public function testExecuteWhenSessionIsNotPersistent() - { - $this->sessionHelperMock->expects($this->once())->method('isPersistent')->will($this->returnValue(false)); - $this->checkoutSessionMock->expects($this->never())->method('setLoadInactive'); - $this->model->execute($this->observerMock); - } - - public function testExecute() - { - $this->sessionHelperMock->expects($this->once())->method('isPersistent')->will($this->returnValue(true)); - $this->customerSessionMock->expects($this->once())->method('isLoggedIn')->will($this->returnValue(false)); - $this->helperMock->expects($this->once())->method('isShoppingCartPersist')->will($this->returnValue(true)); - $this->checkoutSessionMock->expects($this->never())->method('setLoadInactive'); - $this->model->execute($this->observerMock); - } -} diff --git a/app/code/Magento/Persistent/etc/frontend/events.xml b/app/code/Magento/Persistent/etc/frontend/events.xml index 193b9a10818e4..79720695ea6f6 100644 --- a/app/code/Magento/Persistent/etc/frontend/events.xml +++ b/app/code/Magento/Persistent/etc/frontend/events.xml @@ -49,7 +49,7 @@ <observer name="persistent" instance="Magento\Persistent\Observer\SetQuotePersistentDataObserver" /> </event> <event name="custom_quote_process"> - <observer name="persistent" instance="Magento\Persistent\Observer\SetLoadPersistentQuoteObserver" /> + <observer name="persistent" instance="Magento\Persistent\Observer\SetCheckoutSessionPersistentDataObserver" /> </event> <event name="customer_register_success"> <observer name="persistent" instance="Magento\Persistent\Observer\RemovePersistentCookieOnRegisterObserver" /> diff --git a/app/code/Magento/Persistent/etc/webapi_rest/events.xml b/app/code/Magento/Persistent/etc/webapi_rest/events.xml index 1eff845386bf4..79dffa1834563 100644 --- a/app/code/Magento/Persistent/etc/webapi_rest/events.xml +++ b/app/code/Magento/Persistent/etc/webapi_rest/events.xml @@ -22,7 +22,7 @@ <observer name="persistent" instance="Magento\Persistent\Observer\SetQuotePersistentDataObserver" /> </event> <event name="custom_quote_process"> - <observer name="persistent" instance="Magento\Persistent\Observer\SetLoadPersistentQuoteObserver" /> + <observer name="persistent" instance="Magento\Persistent\Observer\SetCheckoutSessionPersistentDataObserver" /> </event> <event name="customer_register_success"> <observer name="persistent" instance="Magento\Persistent\Observer\RemovePersistentCookieOnRegisterObserver" /> diff --git a/app/code/Magento/Persistent/etc/webapi_soap/events.xml b/app/code/Magento/Persistent/etc/webapi_soap/events.xml index 1eff845386bf4..79dffa1834563 100644 --- a/app/code/Magento/Persistent/etc/webapi_soap/events.xml +++ b/app/code/Magento/Persistent/etc/webapi_soap/events.xml @@ -22,7 +22,7 @@ <observer name="persistent" instance="Magento\Persistent\Observer\SetQuotePersistentDataObserver" /> </event> <event name="custom_quote_process"> - <observer name="persistent" instance="Magento\Persistent\Observer\SetLoadPersistentQuoteObserver" /> + <observer name="persistent" instance="Magento\Persistent\Observer\SetCheckoutSessionPersistentDataObserver" /> </event> <event name="customer_register_success"> <observer name="persistent" instance="Magento\Persistent\Observer\RemovePersistentCookieOnRegisterObserver" /> From 46fdf6db5b43313e197b4717ee51ca24cc6c2bd6 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Thu, 20 Sep 2018 22:00:41 +0300 Subject: [PATCH 0070/1158] Update Tests --- .../Catalog/Ui/Component/ColumnFactory.php | 18 +- .../Model/ObjectRegistry.php | 4 +- .../Block/Adminhtml/Edit/Tab/View/Sales.php | 18 +- app/code/Magento/Fedex/Model/Carrier.php | 12 +- app/code/Magento/Store/Model/Store.php | 206 +++++++++--------- .../Model/ResourceModel/Layout/Update.php | 36 +-- 6 files changed, 148 insertions(+), 146 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php index 8daec1fa6ca78..f400a699f7dde 100644 --- a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php +++ b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php @@ -46,14 +46,16 @@ public function __construct(\Magento\Framework\View\Element\UiComponentFactory $ $this->componentFactory = $componentFactory; } - /** - * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute - * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context - * @param array $config - * - * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Create Factory + * + * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context + * @param array $config + * + * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface + * @throws \Magento\Framework\Exception\LocalizedException + */ public function create($attribute, $context, array $config = []) { $columnName = $attribute->getAttributeCode(); diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php index ecc4ff04ab8a7..352948b8338bc 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php @@ -26,7 +26,7 @@ public function __construct($entities) } /** - * Get + * Get Entity * * @param int $entityId * @return \Magento\Framework\DataObject|null @@ -37,7 +37,7 @@ public function get($entityId) } /** - * List + * List Entities * * @return \Magento\Framework\DataObject[] */ diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php index b9442797765c6..38732803aae63 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php @@ -166,15 +166,15 @@ public function getTotals() return $this->_collection->getTotals(); } - /** - * Format price by specified website - * - * @param float $price - * @param null|int $websiteId - * - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Format price by specified website + * + * @param float $price + * @param null|int $websiteId + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function formatCurrency($price, $websiteId = null) { return $this->_storeManager->getWebsite($websiteId)->getBaseCurrency()->format($price); diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 843867e183cac..5a869d44b075d 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -982,12 +982,12 @@ public function getCode($type, $code = '') } } - /** - * Return FeDex currency ISO code by Magento Base Currency Code - * - * @return string 3-digit currency code - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Return FeDex currency ISO code by Magento Base Currency Code + * + * @return string 3-digit currency code + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrencyCode() { $codes = [ diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 47d89112c08ea..d55bf0b5e1cd0 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -460,12 +460,12 @@ protected function _getSession() return $this->_session; } - /** - * Validation rules for store - * - * @return \Zend_Validate_Interface|null - * @throws \Zend_Validate_Exception - */ + /** + * Validation rules for store + * + * @return \Zend_Validate_Interface|null + * @throws \Zend_Validate_Exception + */ protected function _getValidationRulesBeforeSave() { $validator = new \Magento\Framework\Validator\DataObject(); @@ -487,15 +487,15 @@ protected function _getValidationRulesBeforeSave() return $validator; } - /** - * Loading store data - * - * @param mixed $key - * @param string $field - * - * @return $this - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Loading store data + * + * @param mixed $key + * @param string $field + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function load($key, $field = null) { if (!is_numeric($key) && $field === null) { @@ -565,12 +565,12 @@ public function setWebsite(Website $website) $this->setWebsiteId($website->getId()); } - /** - * Retrieve store website - * - * @return Website|bool - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve store website + * + * @return Website|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getWebsite() { if ($this->getWebsiteId() === null) { @@ -579,15 +579,15 @@ public function getWebsite() return $this->websiteRepository->getById($this->getWebsiteId()); } - /** - * Retrieve url using store configuration specific - * - * @param string $route - * @param array $params - * - * @return string - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve url using store configuration specific + * + * @param string $route + * @param array $params + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getUrl($route = '', $params = []) { /** @var $url UrlInterface */ @@ -883,14 +883,14 @@ public function getDefaultCurrency() return $currency; } - /** - * Set current store currency code - * - * @param string $code - * - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Set current store currency code + * + * @param string $code + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function setCurrentCurrencyCode($code) { $code = strtoupper($code); @@ -976,12 +976,12 @@ public function getAllowedCurrencies() return explode(',', $this->getConfig($this->_currencyInstalled)); } - /** - * Retrieve store current currency - * - * @return Currency - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Retrieve store current currency + * + * @return Currency + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrency() { $currency = $this->getData('current_currency'); @@ -999,23 +999,23 @@ public function getCurrentCurrency() return $currency; } - /** - * Retrieve current currency rate - * - * @return float - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Retrieve current currency rate + * + * @return float + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrencyRate() { return $this->getBaseCurrency()->getRate($this->getCurrentCurrency()); } - /** - * Retrieve root category identifier - * - * @return int - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve root category identifier + * + * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getRootCategoryId() { if (!$this->getGroup()) { @@ -1036,12 +1036,12 @@ public function setGroup(Group $group) return $this; } - /** - * Retrieve group model - * - * @return Group|bool - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve group model + * + * @return Group|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getGroup() { if (null === $this->getGroupId()) { @@ -1144,12 +1144,12 @@ public function getDefaultGroupId() return $this->_getData('default_group_id'); } - /** - * Check if store can be deleted - * - * @return boolean - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Check if store can be deleted + * + * @return boolean + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isCanDelete() { if (!$this->getId()) { @@ -1159,13 +1159,13 @@ public function isCanDelete() return $this->getGroup()->getStoresCount() > 1; } - /** - * Check if store is default - * - * @return boolean - * @since 100.1.0 - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Check if store is default + * + * @return boolean + * @since 100.1.0 + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isDefault() { if (!$this->getId() && $this->getWebsite() && $this->getWebsite()->getStoresCount() == 0) { @@ -1174,16 +1174,16 @@ public function isDefault() return $this->getGroup()->getDefaultStoreId() == $this->getId(); } - /** - * Retrieve current url for store - * - * @param bool $fromStore - * - * @return string - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve current url for store + * + * @param bool $fromStore + * + * @return string + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrentUrl($fromStore = true) { $sidQueryParam = $this->_sidResolver->getSessionIdQueryParam($this->_getSession()); @@ -1254,24 +1254,24 @@ public function isActive() return (bool)$this->_getData('is_active'); } - /** - * Protect delete from non admin area - * - * @return $this - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Protect delete from non admin area + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function beforeDelete() { $this->_configDataResource->clearScopeData(ScopeInterface::SCOPE_STORES, $this->getId()); return parent::beforeDelete(); } - /** - * Rewrite in order to clear configuration cache - * - * @return $this - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Rewrite in order to clear configuration cache + * + * @return $this + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function afterDelete() { $store = $this; @@ -1326,12 +1326,12 @@ public function isReadOnly($value = null) return $this->_isReadOnly; } - /** - * Retrieve store group name - * - * @return string - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve store group name + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getFrontendName() { if (null === $this->_frontendName) { diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index a951954600365..8817a947f835e 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -45,16 +45,16 @@ protected function _construct() $this->_init('layout_update', 'layout_update_id'); } - /** - * Retrieve layout updates by handle - * - * @param string $handle - * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface $store - * - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Retrieve layout updates by handle + * + * @param string $handle + * @param \Magento\Framework\View\Design\ThemeInterface $theme + * @param \Magento\Framework\App\ScopeInterface $store + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function fetchUpdatesByHandle( $handle, \Magento\Framework\View\Design\ThemeInterface $theme, @@ -74,14 +74,14 @@ public function fetchUpdatesByHandle( return $this->layoutUpdateCache[$cacheKey][$handle] ?? ''; } - /** - * Get select to fetch updates by handle - * - * @param bool $loadAllUpdates - * - * @return \Magento\Framework\DB\Select - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Get select to fetch updates by handle + * + * @param bool $loadAllUpdates + * + * @return \Magento\Framework\DB\Select + * @throws \Magento\Framework\Exception\LocalizedException + */ protected function _getFetchUpdatesByHandleSelect($loadAllUpdates = false) { //@todo Why it also loads layout updates for store_id=0, isn't it Admin Store View? From 441a98190a29baa239b419fdb2f492ef3a82431d Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 21 Sep 2018 09:08:55 +0200 Subject: [PATCH 0071/1158] Added correct path to the phpunit file --- .travis.yml | 3 ++- dev/tests/api-functional/phpunit_graphql.xml.dist | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e909bb1980752..a80460095ce01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,5 +62,6 @@ script: # The scripts for grunt/phpunit type tests - if [ $TEST_SUITE == "functional" ]; then dev/tests/functional/vendor/phpunit/phpunit/phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi + - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js" ] && [ $TEST_SUITE != "api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi + - if [ $TEST_SUITE == "api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE/phpunit_graphql.xml.dist; fi - if [ $TEST_SUITE == "js" ]; then grunt $GRUNT_COMMAND; fi diff --git a/dev/tests/api-functional/phpunit_graphql.xml.dist b/dev/tests/api-functional/phpunit_graphql.xml.dist index 4a57c338ca3a2..955a3a8953fa8 100644 --- a/dev/tests/api-functional/phpunit_graphql.xml.dist +++ b/dev/tests/api-functional/phpunit_graphql.xml.dist @@ -27,7 +27,7 @@ <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/> <!-- Webserver URL --> - <const name="TESTS_BASE_URL" value="http://magento.url"/> + <const name="TESTS_BASE_URL" value="http://magento2.travis"/> <!-- Webserver API user --> <const name="TESTS_WEBSERVICE_USER" value="admin"/> <!-- Webserver API key --> From df755861a85c2087ba71e7adfa0884fdf46c2544 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 21 Sep 2018 10:55:42 +0200 Subject: [PATCH 0072/1158] Test api-functional execution with phpunit.xml.dist --- .travis.yml | 4 +- dev/tests/api-functional/phpunit.xml.dist | 56 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 dev/tests/api-functional/phpunit.xml.dist diff --git a/.travis.yml b/.travis.yml index a80460095ce01..c6077564b923d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,6 +62,6 @@ script: # The scripts for grunt/phpunit type tests - if [ $TEST_SUITE == "functional" ]; then dev/tests/functional/vendor/phpunit/phpunit/phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js" ] && [ $TEST_SUITE != "api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - - if [ $TEST_SUITE == "api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE/phpunit_graphql.xml.dist; fi + - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi + #- if [ $TEST_SUITE == "api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE/phpunit_graphql.xml.dist; fi - if [ $TEST_SUITE == "js" ]; then grunt $GRUNT_COMMAND; fi diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist new file mode 100644 index 0000000000000..955a3a8953fa8 --- /dev/null +++ b/dev/tests/api-functional/phpunit.xml.dist @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * PHPUnit configuration for GraphQL web API functional tests. + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.2/phpunit.xsd" + colors="true" + columns="max" + beStrictAboutTestsThatDoNotTestAnything="false" + bootstrap="./framework/bootstrap.php" +> + <!-- Test suites definition --> + <testsuites> + <testsuite name="Magento GraphQL web API functional tests"> + <directory suffix="Test.php">testsuite/Magento/GraphQl</directory> + </testsuite> + </testsuites> + + <!-- PHP INI settings and constants definition --> + <php> + <includePath>./testsuite</includePath> + <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> + <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/> + <!-- Webserver URL --> + <const name="TESTS_BASE_URL" value="http://magento2.travis"/> + <!-- Webserver API user --> + <const name="TESTS_WEBSERVICE_USER" value="admin"/> + <!-- Webserver API key --> + <const name="TESTS_WEBSERVICE_APIKEY" value="123123q"/> + <!-- Define if debugger should be started using XDEBUG_SESSION cookie --> + <const name="TESTS_XDEBUG_ENABLED" value="false"/> + <!-- Define XDEBUG_SESSION cookie value--> + <const name="TESTS_XDEBUG_SESSION" value="phpstorm" /> + + <ini name="date.timezone" value="America/Los_Angeles"/> + + <!-- Semicolon-separated 'glob' patterns, that match global XML configuration files --> + <const name="TESTS_GLOBAL_CONFIG_DIR" value="../../../app/etc"/> + <!-- Whether to cleanup the application before running tests or not --> + <const name="TESTS_CLEANUP" value="enabled"/> + <!--Defines if Magento should be installed before tests execution--> + <const name="TESTS_MAGENTO_INSTALLATION" value="disabled"/> + <!-- Magento mode for tests execution. Possible values are "default", "developer" and "production". --> + <const name="TESTS_MAGENTO_MODE" value="default"/> + </php> + + <!-- Test listeners --> + <listeners> + <listener class="Magento\TestFramework\Event\PhpUnit"/> + </listeners> +</phpunit> From 636142edf17227f7d72ccf0d13555971276aa6f7 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 21 Sep 2018 11:16:01 +0200 Subject: [PATCH 0073/1158] Test api-functional execution with production mode enabled --- dev/tests/api-functional/phpunit.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist index 955a3a8953fa8..a55531aba87e2 100644 --- a/dev/tests/api-functional/phpunit.xml.dist +++ b/dev/tests/api-functional/phpunit.xml.dist @@ -46,7 +46,7 @@ <!--Defines if Magento should be installed before tests execution--> <const name="TESTS_MAGENTO_INSTALLATION" value="disabled"/> <!-- Magento mode for tests execution. Possible values are "default", "developer" and "production". --> - <const name="TESTS_MAGENTO_MODE" value="default"/> + <const name="TESTS_MAGENTO_MODE" value="production"/> </php> <!-- Test listeners --> From 1148f85e42022e77817e33a901bef5153a7cf108 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Fri, 21 Sep 2018 15:11:30 +0300 Subject: [PATCH 0074/1158] MAGETWO-59265: Import doesn't allow to set default value per store view (dropdown fields) - Changed logic of setting default value of attributes by store view during import --- .../Model/Import/Product/Type/AbstractType.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php index 8b04b7ec3532f..3b6caef66ce6c 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php @@ -543,10 +543,9 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe } else { $resultAttrs[$attrCode] = $rowData[$attrCode]; } - } elseif (array_key_exists($attrCode, $rowData)) { + } elseif (array_key_exists($attrCode, $rowData) && empty($rowData['_store'])) { $resultAttrs[$attrCode] = $rowData[$attrCode]; - } elseif ($withDefaultValue && null !== $attrParams['default_value'] - && 'select' == $attrParams['type'] && null === $rowData['_store']) { + } elseif ($withDefaultValue && null !== $attrParams['default_value'] && empty($rowData['_store'])) { $resultAttrs[$attrCode] = $attrParams['default_value']; } } From bb949b4f3a0322f1ab73b19c2680d12859294038 Mon Sep 17 00:00:00 2001 From: Aleksey Tsoy <aleksey_tsoy@epam.com> Date: Fri, 21 Sep 2018 20:50:29 +0600 Subject: [PATCH 0075/1158] MAGETWO-91745: Product pages load blank page - Added automated test --- .../Mftf/Data/CatalogAttributeSetData.xml | 16 ++++++++++++ .../Catalog/Test/Mftf/Data/ProductData.xml | 14 +++++++++++ .../Metadata/catalog_attribute_set-meta.xml | 25 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Data/CatalogAttributeSetData.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_attribute_set-meta.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CatalogAttributeSetData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogAttributeSetData.xml new file mode 100644 index 0000000000000..d78c03a51dd75 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogAttributeSetData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="CatalogAttributeSet" type="CatalogAttributeSet"> + <data key="attribute_set_name" unique="suffix">test_set_</data> + <data key="attributeGroupId">7</data> + <data key="skeletonId">4</data> + </entity> +</entities> \ No newline at end of file diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 9ae551b69d388..3da3272567c9d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -301,6 +301,20 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="SimpleProductWithCustomAttributeSet" type="product"> + <data key="sku" unique="suffix">testSku</data> + <data key="type_id">simple</data> + <var key="attribute_set_id" entityKey="attribute_set_id" entityType="CatalogAttributeSet"/> + <data key="visibility">4</data> + <data key="name" unique="suffix">testProductName</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">testurlkey</data> + <data key="status">1</data> + <data key="weight">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> <entity name="productWithOptions" type="product"> <var key="sku" entityType="product" entityKey="sku" /> <data key="file">magento.jpg</data> diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_attribute_set-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_attribute_set-meta.xml new file mode 100644 index 0000000000000..9ef7b507812a0 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_attribute_set-meta.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="AddCatalogAttributeToAttributeSet" dataType="CatalogAttributeSet" type="create" auth="adminOauth" url="/V1/products/attribute-sets" method="POST"> + <contentType>application/json</contentType> + <object key="attributeSet" dataType="CatalogAttributeSet"> + <field key="attribute_set_name">string</field> + <field key="sort_order">integer</field> + </object> + <field key="skeletonId">integer</field> + </operation> + <operation name="DeleteCatalogAttributeFromAttributeSet" dataType="CatalogAttributeSet" type="delete" auth="adminOauth" url="/V1/products/attribute-sets/{attribute_set_id}" method="DELETE"> + <contentType>application/json</contentType> + </operation> + <operation name="GetCatalogAttributesFromDefaultSet" dataType="CatalogAttributeSet" type="get" auth="adminOauth" url="/V1/products/attribute-sets/{attribute_set_id}" method="GET"> + <contentType>application/json</contentType> + </operation> +</operations> \ No newline at end of file From b35b68130265163f2ed151ff94e0d9f7fc63d44c Mon Sep 17 00:00:00 2001 From: Stsiapan Korf <Stsiapan_Korf@epam.com> Date: Fri, 21 Sep 2018 18:57:25 +0300 Subject: [PATCH 0076/1158] MAGETWO-91702: Shipping method Table Rates settings gets from wrong store - Get store id from quote for shipping rates --- .../Magento/Quote/Model/Quote/Address.php | 90 +++++++++---------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 3eb5d68885035..11beffe5711b9 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -965,6 +965,7 @@ public function collectShippingRates() /** * Request shipping rates for entire address or specified address item + * * Returns true if current selected shipping method code corresponds to one of the found rates * * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item @@ -1002,7 +1003,7 @@ public function requestShippingRates(\Magento\Quote\Model\Quote\Item\AbstractIte /** * Store and website identifiers specified from StoreManager */ - $request->setStoreId($this->storeManager->getStore()->getId()); + $request->setStoreId($this->getQuote()->getStoreId() ?? $this->storeManager->getStore()->getId()); $request->setWebsiteId($this->storeManager->getWebsite()->getId()); $request->setFreeShipping($this->getFreeShipping()); /** @@ -1348,7 +1349,7 @@ public function getAllBaseTotalAmounts() /******************************* End Total Collector Interface *******************************************/ /** - * {@inheritdoc} + * @inheritdoc */ protected function _getValidationRulesBeforeSave() { @@ -1356,7 +1357,7 @@ protected function _getValidationRulesBeforeSave() } /** - * {@inheritdoc} + * @inheritdoc */ public function getCountryId() { @@ -1364,7 +1365,7 @@ public function getCountryId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCountryId($countryId) { @@ -1372,7 +1373,7 @@ public function setCountryId($countryId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getStreet() { @@ -1381,7 +1382,7 @@ public function getStreet() } /** - * {@inheritdoc} + * @inheritdoc */ public function setStreet($street) { @@ -1389,7 +1390,7 @@ public function setStreet($street) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCompany() { @@ -1397,7 +1398,7 @@ public function getCompany() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCompany($company) { @@ -1405,7 +1406,7 @@ public function setCompany($company) } /** - * {@inheritdoc} + * @inheritdoc */ public function getTelephone() { @@ -1413,7 +1414,7 @@ public function getTelephone() } /** - * {@inheritdoc} + * @inheritdoc */ public function setTelephone($telephone) { @@ -1421,7 +1422,7 @@ public function setTelephone($telephone) } /** - * {@inheritdoc} + * @inheritdoc */ public function getFax() { @@ -1429,7 +1430,7 @@ public function getFax() } /** - * {@inheritdoc} + * @inheritdoc */ public function setFax($fax) { @@ -1437,7 +1438,7 @@ public function setFax($fax) } /** - * {@inheritdoc} + * @inheritdoc */ public function getPostcode() { @@ -1445,7 +1446,7 @@ public function getPostcode() } /** - * {@inheritdoc} + * @inheritdoc */ public function setPostcode($postcode) { @@ -1453,7 +1454,7 @@ public function setPostcode($postcode) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCity() { @@ -1461,7 +1462,7 @@ public function getCity() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCity($city) { @@ -1469,7 +1470,7 @@ public function setCity($city) } /** - * {@inheritdoc} + * @inheritdoc */ public function getFirstname() { @@ -1477,7 +1478,7 @@ public function getFirstname() } /** - * {@inheritdoc} + * @inheritdoc */ public function setFirstname($firstname) { @@ -1485,7 +1486,7 @@ public function setFirstname($firstname) } /** - * {@inheritdoc} + * @inheritdoc */ public function getLastname() { @@ -1493,7 +1494,7 @@ public function getLastname() } /** - * {@inheritdoc} + * @inheritdoc */ public function setLastname($lastname) { @@ -1501,7 +1502,7 @@ public function setLastname($lastname) } /** - * {@inheritdoc} + * @inheritdoc */ public function getMiddlename() { @@ -1509,7 +1510,7 @@ public function getMiddlename() } /** - * {@inheritdoc} + * @inheritdoc */ public function setMiddlename($middlename) { @@ -1517,7 +1518,7 @@ public function setMiddlename($middlename) } /** - * {@inheritdoc} + * @inheritdoc */ public function getPrefix() { @@ -1525,7 +1526,7 @@ public function getPrefix() } /** - * {@inheritdoc} + * @inheritdoc */ public function setPrefix($prefix) { @@ -1533,7 +1534,7 @@ public function setPrefix($prefix) } /** - * {@inheritdoc} + * @inheritdoc */ public function getSuffix() { @@ -1541,7 +1542,7 @@ public function getSuffix() } /** - * {@inheritdoc} + * @inheritdoc */ public function setSuffix($suffix) { @@ -1549,7 +1550,7 @@ public function setSuffix($suffix) } /** - * {@inheritdoc} + * @inheritdoc */ public function getVatId() { @@ -1557,7 +1558,7 @@ public function getVatId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setVatId($vatId) { @@ -1565,7 +1566,7 @@ public function setVatId($vatId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCustomerId() { @@ -1573,7 +1574,7 @@ public function getCustomerId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerId($customerId) { @@ -1581,7 +1582,7 @@ public function setCustomerId($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getEmail() { @@ -1594,7 +1595,7 @@ public function getEmail() } /** - * {@inheritdoc} + * @inheritdoc */ public function setEmail($email) { @@ -1602,7 +1603,7 @@ public function setEmail($email) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRegion($region) { @@ -1610,7 +1611,7 @@ public function setRegion($region) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRegionId($regionId) { @@ -1618,7 +1619,7 @@ public function setRegionId($regionId) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRegionCode($regionCode) { @@ -1626,7 +1627,7 @@ public function setRegionCode($regionCode) } /** - * {@inheritdoc} + * @inheritdoc */ public function getSameAsBilling() { @@ -1634,7 +1635,7 @@ public function getSameAsBilling() } /** - * {@inheritdoc} + * @inheritdoc */ public function setSameAsBilling($sameAsBilling) { @@ -1642,7 +1643,7 @@ public function setSameAsBilling($sameAsBilling) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCustomerAddressId() { @@ -1650,7 +1651,7 @@ public function getCustomerAddressId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerAddressId($customerAddressId) { @@ -1681,9 +1682,7 @@ public function setSaveInAddressBook($saveInAddressBook) //@codeCoverageIgnoreEnd /** - * {@inheritdoc} - * - * @return \Magento\Quote\Api\Data\AddressExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -1691,10 +1690,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} - * - * @param \Magento\Quote\Api\Data\AddressExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Quote\Api\Data\AddressExtensionInterface $extensionAttributes) { @@ -1712,7 +1708,7 @@ public function getShippingMethod() } /** - * {@inheritdoc} + * @inheritdoc */ protected function getCustomAttributesCodes() { From 93f6e5e17d024e00cea0bcf6254afc47cf53b73a Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Sat, 22 Sep 2018 11:46:44 +0200 Subject: [PATCH 0077/1158] Added schema concept for working with cart addresses and shipping methods --- .../Magento/QuoteGraphQl/etc/schema.graphqls | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 06b3328b9e058..b10575171781e 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -1,10 +1,82 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. +type Query { + getAvailableShippingMethodsOnCart(input: AvailableShippingMethodsOnCartInput): AvailableShippingMethodsOnCartOutput @doc(description:"Returns available shipping methods for cart by address/address_id") +} + type Mutation { createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") + setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput + setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput + setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput +} + +input SetShippingAddressesOnCartInput { + cart_id: String! + customer_address_id: Int # Can be provided in one-page checkout and is required for multi-shipping checkout + address: CartAddressInput + cart_items: [CartItemQuantityInput!] +} + +input CartItemQuantityInput { + cart_item_id: Int! + quantity: Float! +} + +input SetBillingAddressOnCartInput { + cart_id: String! + customer_address_id: Int + address: CartAddressInput + # TODO: consider adding "Same as shipping" option +} + +input CartAddressInput { + firstname: String! + lastname: String! + company: String + street: [String!]! + city: String! + region: String + postcode: String + country_code: String! + telephone: String! + save_in_address_book: Boolean! +} + +input SetShippingMethodsOnCartInput { + shipping_methods: [ShippingMethodForAddressInput!]! +} + +input ShippingMethodForAddressInput { + cart_address_id: String! + shipping_method_code: String! +} + +type SetBillingAddressOnCartOutput { + cart: Cart! +} + +type SetShippingAddressesOnCartOutput { + cart: Cart! +} + +type SetShippingMethodsOnCartOutput { + cart: Cart! +} + +# If no address is provided, the system get address assigned to a quote +# If there's no address at all - the system returns all shipping methods +type AvailableShippingMethodsOnCartInput { + cart_id: String! + customer_address_id: Int + address: CartAddressInput +} + +type AvailableShippingMethodsOnCartOutput { + available_shipping_methods: [CheckoutShippingMethod] } input ApplyCouponToCartInput { @@ -18,12 +90,56 @@ type ApplyCouponToCartOutput { type Cart { applied_coupon: AppliedCoupon + addresses: [CartAddress]! } type CartAddress { + firstname: String! + lastname: String! + company: String + street: [String!]! + city: String! + region: CartAddressRegion + postcode: String + country: CartAddressCountry! + telephone: String! + address_type: AdressTypeEnum! + selected_shipping_method: CheckoutShippingMethod + available_shipping_methods: [CheckoutShippingMethod]! + items_weight: Float + customer_notes: String + cart_items: [CartItemQuantity] applied_coupon: AppliedCoupon } +type CartItemQuantity { + cart_item_id: String! + quantity: Float! +} + +type CartAddressRegion { + code: String + label: String +} + +type CartAddressCountry { + code: String + label: String +} + +type CheckoutShippingMethod { + code: String + label: String + free_shipping: Boolean! + error_message: String + # TODO: Add more complex structure for shipping rates +} + +enum AdressTypeEnum { + SHIPPING + BILLING +} + type AppliedCoupon { code: String! } From 79a968ba6bbb54ce8c3e5714bba164f924fc74f3 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Sat, 22 Sep 2018 10:28:58 +0000 Subject: [PATCH 0078/1158] graphQl-44: refactoring of format strategy Signed-off-by: vitaliyboyko <v.boyko@atwix.com> --- .../Resolver/Product/ProductTextAttribute.php | 33 +++++++++---------- .../ProductTextAttribute/FormatInterface.php | 2 +- .../ProductTextAttribute/FormatList.php | 28 +++++++++------- .../Product/ProductTextAttribute/Html.php | 2 +- .../Magento/CatalogGraphQl/etc/graphql/di.xml | 7 ++++ .../CatalogGraphQl/etc/schema.graphqls | 12 +++---- 6 files changed, 46 insertions(+), 38 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php index f04609f91c86d..9c1212667acf3 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php @@ -8,7 +8,7 @@ namespace Magento\CatalogGraphQl\Model\Resolver\Product; use Magento\Catalog\Model\Product; -use Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute\FormatFactory; +use Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\FormatList; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\Resolver\Value; use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; @@ -18,9 +18,12 @@ /** * Resolve rendered content for attributes where HTML content is allowed */ -class ProductTextareaAttribute implements ResolverInterface +class ProductTextAttribute implements ResolverInterface { - const DEFAULT_CONTENT_FORMAT_IDENTIFIER = 'html'; + /** + * @var FormatList + */ + private $formatList; /** * @var ValueFactory @@ -28,20 +31,20 @@ class ProductTextareaAttribute implements ResolverInterface private $valueFactory; /** - * @var FormatFactory + * @var string */ - private $formatFactory; + private $defaultFormat = 'html'; /** * @param ValueFactory $valueFactory - * @param FormatFactory $formatFactory + * @param FormatList $formatFactory */ public function __construct( ValueFactory $valueFactory, - FormatFactory $formatFactory + FormatList $formatFactory ) { $this->valueFactory = $valueFactory; - $this->formatFactory = $formatFactory; + $this->formatList = $formatFactory; } /** @@ -55,22 +58,16 @@ public function resolve( array $args = null ): Value { if (!isset($value['model'])) { - $result = function () { - return null; - }; + $result = []; return $this->valueFactory->create($result); } /* @var $product Product */ $product = $value['model']; $fieldName = $field->getName(); - $formatIdentifier = $args['format'] ?? self::DEFAULT_CONTENT_FORMAT_IDENTIFIER; - $format = $this->formatFactory->create($formatIdentifier); - $attribute = ['content' => $format->getContent($product, $fieldName)]; - - $result = function () use ($attribute) { - return $attribute; - }; + $formatIdentifier = $args['format'] ?? $this->defaultFormat; + $format = $this->formatList->create($formatIdentifier); + $result = ['content' => $format->getContent($product, $fieldName)]; return $this->valueFactory->create($result); } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php index fae685b75c060..2cf702bf18466 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute; +namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; use Magento\Catalog\Model\Product as ModelProduct; diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php index 97e0be3763f1d..2e2f21d643092 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php @@ -9,35 +9,39 @@ use Magento\Framework\ObjectManagerInterface; -class FormatFactory +class FormatList { /** * @var ObjectManagerInterface */ private $objectManager; + /** + * @var string + */ + private $formats; + /** * @param ObjectManagerInterface $objectManager + * @param array $formats */ - public function __construct(ObjectManagerInterface $objectManager) - { + public function __construct( + ObjectManagerInterface $objectManager, + array $formats + ) { $this->objectManager = $objectManager; + $this->formats = $formats; } /** * @param string $formatIdentifier - * @param array $data * @return FormatInterface */ - public function create(string $formatIdentifier, $data = []) : FormatInterface + public function create(string $formatIdentifier) : FormatInterface { - $formatClassName = 'Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute\\' . ucfirst($formatIdentifier); - $formatInstance = $this->objectManager->create($formatClassName, $data); - if (false == $formatInstance instanceof FormatInterface) { - throw new \InvalidArgumentException( - $formatInstance . ' is not instance of \Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute\FormatInterface' - ); - } + $formatClassName = 'Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\\' . ucfirst($formatIdentifier); + $formatInstance = $this->objectManager->get($formatClassName); + return $formatInstance; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php index 8201c40427dc9..75c29a3f78fac 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextareaAttribute; +namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; use Magento\Catalog\Helper\Output as OutputHelper; diff --git a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml index 68a292ede6b4a..8d4ca97001d3d 100644 --- a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml @@ -63,6 +63,13 @@ <argument name="collectionProcessor" xsi:type="object">Magento\Catalog\Model\Api\SearchCriteria\ProductCollectionProcessor</argument> </arguments> </type> + <type name="Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\FormatList"> + <arguments> + <argument name="formats" xsi:type="array"> + <item name="html" xsi:type="string">Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\Html</item> + </argument> + </arguments> + </type> <virtualType name="Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ProductFilterProcessor" type="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor"> <arguments> <argument name="customFilters" xsi:type="array"> diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index a9c4a1b4bd8ae..3f3282ed5f529 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ProductTextareaAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") - short_description: ProductTextareaAttribute @doc(description: "A short description of the product. Its use depends on the theme.") + description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") + short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") @@ -552,9 +552,9 @@ type SortFields @doc(description: "SortFields contains a default value for sort options: [SortField] @doc(description: "Available sort fields") } -type ProductTextareaAttribute { +type ProductTextAttribute { content ( - format: String! @doc(description: "The format of content") -): String - @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextareaAttribute") + format: String @doc(description: "The format of content") +): String @doc(description: "The format of content") + @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") } From e327bb695bf2cb01240d5d442d5d269fb3c50064 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Sat, 22 Sep 2018 15:18:18 +0000 Subject: [PATCH 0079/1158] graphQl: shipping address concept Signed-off-by: vitaliyboyko <v.boyko@atwix.com> --- .../SetShippingAddressesOnCart.php | 104 ++++++++++++++++++ .../Magento/QuoteGraphQl/etc/schema.graphqls | 2 +- 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php new file mode 100644 index 0000000000000..9d54792136367 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php @@ -0,0 +1,104 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress; + +use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\ShippingAddressManagementInterface; + +/** + * @inheritdoc + */ +class SetShippingAddressesOnCart implements ResolverInterface +{ + /** + * @var ShippingAddressManagementInterface + */ + private $shippingAddressManagement; + + /** + * @var AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @var Address + */ + private $addressModel; + /** + * @var DataObjectHelper + */ + private $dataObjectHelper; + + /** + * @var MaskedQuoteIdToQuoteIdInterface + */ + private $maskedQuoteIdToQuoteId; + + /** + * @param ShippingAddressManagementInterface $shippingAddressManagement + * @param AddressRepositoryInterface $addressRepository + * @param Address $addressModel + * @param DataObjectHelper $dataObjectHelper + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ + public function __construct( + ShippingAddressManagementInterface $shippingAddressManagement, + AddressRepositoryInterface $addressRepository, + Address $addressModel, + DataObjectHelper $dataObjectHelper, + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { + $this->shippingAddressManagement = $shippingAddressManagement; + $this->addressRepository = $addressRepository; + $this->addressModel = $addressModel; + $this->dataObjectHelper = $dataObjectHelper; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($args['input']['cart_id'])) { + throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); + } + $maskedCartId = $args['input']['cart_id']; + $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); + + $customerAddressId = $args['input']['customer_address_id'] ?? 0; + $address = $args['input']['address'] ?? null; + $cartItems = $args['input']['cart_items'] ?? []; + + if (!$customerAddressId && !$address) { + throw new GraphQlInputException(__('Query should contain either address id or address input.')); + } + + if (!$cartItems) { + if($customerAddressId) { + $customerAddress = $this->addressRepository->getById($customerAddressId); + $shippingAddress = $this->addressModel->importCustomerAddressData($customerAddress); + $this->shippingAddressManagement->assign($cartId, $shippingAddress); + } else { + $shippingAddress = $this->addressModel->addData($address); + $this->shippingAddressManagement->assign($cartId, $shippingAddress); + } + } else { + //TODO: implement multi shipping address assign flow + } + + return []; + } +} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index b10575171781e..d13240a23140b 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -9,7 +9,7 @@ type Mutation { createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") - setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput + setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ShippingAddress\\SetShippingAddressesOnCart") setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput } From 1b5f7c5db19aec08fd832fe82a59e691ce2edf81 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Sun, 23 Sep 2018 01:02:47 +0300 Subject: [PATCH 0080/1158] fix tests --- .../Catalog/Ui/Component/ColumnFactory.php | 8 + .../Component/Listing/Columns/Thumbnail.php | 4 + .../Model/ObjectRegistry.php | 3 + .../Block/Adminhtml/Edit/Tab/View/Sales.php | 4 + .../Model/Address/AbstractAddress.php | 26 ++- app/code/Magento/Fedex/Model/Carrier.php | 18 +- .../IntegrationFactory.php | 2 +- .../DataProvider/NotificationDataProvider.php | 78 +++++++-- .../Magento/Sales/Model/Order/Address.php | 156 ++++++++++++++---- .../Sales/Model/Order/Payment/Info.php | 7 +- .../Sales/Model/Order/Payment/Transaction.php | 60 +++++-- .../Model/Carrier/AbstractCarrierOnline.php | 13 +- app/code/Magento/Store/Model/Store.php | 14 ++ .../Model/ResourceModel/Layout/Update.php | 4 +- 14 files changed, 317 insertions(+), 80 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php index f400a699f7dde..1903bcd144831 100644 --- a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php +++ b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php @@ -6,6 +6,8 @@ namespace Magento\Catalog\Ui\Component; /** + * Column Factory + * * @api * @since 100.0.2 */ @@ -86,7 +88,10 @@ public function create($attribute, $context, array $config = []) } /** + * Get Js Component + * * @param string $dataType + * * @return string */ protected function getJsComponent($dataType) @@ -95,7 +100,10 @@ protected function getJsComponent($dataType) } /** + * Get Data Type + * * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * * @return string */ protected function getDataType($attribute) diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php index dc3c94f384632..09c9782fc0e32 100644 --- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php +++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php @@ -9,6 +9,8 @@ use Magento\Framework\View\Element\UiComponent\ContextInterface; /** + * Class Thumbnail + * * @api * @since 100.0.2 */ @@ -67,6 +69,8 @@ public function prepareDataSource(array $dataSource) } /** + * Get Alt + * * @param array $row * * @return null|string diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php index 352948b8338bc..a048c216139e3 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php @@ -5,6 +5,9 @@ */ namespace Magento\CatalogUrlRewrite\Model; +/** + * Class ObjectRegistry + */ class ObjectRegistry { /** diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php index 38732803aae63..5eeacca4c73a5 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php @@ -151,6 +151,8 @@ public function getWebsiteCount($websiteId) } /** + * Returns Grouped Collection Rows + * * @return array */ public function getRows() @@ -159,6 +161,8 @@ public function getRows() } /** + * Return totals data + * * @return \Magento\Framework\DataObject */ public function getTotals() diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 2c0c7812ca669..caa2761a3dc3d 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -271,7 +271,8 @@ public function setStreet($street) * Enforce format of the street field or other multiline custom attributes * * @param array|string $key - * @param null $value + * @param array|string|null $value + * * @return \Magento\Framework\DataObject */ public function setData($key, $value = null) @@ -286,6 +287,7 @@ public function setData($key, $value = null) /** * Check that address can have multiline attribute by this code (as street or some custom attribute) + * * @param string $code * @return bool */ @@ -403,6 +405,8 @@ public function getRegionCode() } /** + * Return Region ID + * * @return int */ public function getRegionId() @@ -425,6 +429,8 @@ public function getRegionId() } /** + * Return Country + * * @return int */ public function getCountry() @@ -502,6 +508,8 @@ public function getConfig() } /** + * Processing object before save data + * * @return $this */ public function beforeSave() @@ -516,10 +524,12 @@ public function beforeSave() * * @param int|null $defaultBillingAddressId * @param int|null $defaultShippingAddressId + * * @return AddressInterface * Use Api/Data/AddressInterface as a result of service operations. Don't rely on the model to provide * the instance of Api/Data/AddressInterface * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Magento\Framework\Exception\LocalizedException */ public function getDataModel($defaultBillingAddressId = null, $defaultShippingAddressId = null) { @@ -591,6 +601,8 @@ public function validate() } /** + * Create Region Instance + * * @return \Magento\Directory\Model\Region */ protected function _createRegionInstance() @@ -599,6 +611,8 @@ protected function _createRegionInstance() } /** + * Create Country Instance + * * @return \Magento\Directory\Model\Country */ protected function _createCountryInstance() @@ -608,6 +622,7 @@ protected function _createCountryInstance() /** * Unset Region from address + * * @return $this * @since 100.2.0 */ @@ -617,8 +632,11 @@ public function unsRegion() } /** + * Is Company Required + * * @return bool * @since 100.2.0 + * @throws \Magento\Framework\Exception\LocalizedException */ protected function isCompanyRequired() { @@ -626,8 +644,11 @@ protected function isCompanyRequired() } /** + * Is Telephone Required + * * @return bool * @since 100.2.0 + * @throws \Magento\Framework\Exception\LocalizedException */ protected function isTelephoneRequired() { @@ -635,8 +656,11 @@ protected function isTelephoneRequired() } /** + * Is Fax Required + * * @return bool * @since 100.2.0 + * @throws \Magento\Framework\Exception\LocalizedException */ protected function isFaxRequired() { diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 5a869d44b075d..955345851e67a 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -1439,6 +1439,8 @@ protected function _doShipmentRequest(\Magento\Framework\DataObject $request) } /** + * Return Tracking Number + * * @param array|object $trackingIds * @return string */ @@ -1453,10 +1455,10 @@ function ($val) { } /** - * For multi package shipments. Delete requested shipments if the current shipment - * request is failed + * For multi package shipments. Delete requested shipments if the current shipment request is failed * * @param array $data + * * @return bool */ public function rollBack($data) @@ -1476,6 +1478,7 @@ public function rollBack($data) * Return container types of carrier * * @param \Magento\Framework\DataObject|null $params + * * @return array|bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ @@ -1543,6 +1546,7 @@ public function getContainerTypesFilter() * Return delivery confirmation types of carrier * * @param \Magento\Framework\DataObject|null $params + * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -1553,6 +1557,7 @@ public function getDeliveryConfirmationTypes(\Magento\Framework\DataObject $para /** * Recursive replace sensitive fields in debug data by the mask + * * @param string $data * @return string */ @@ -1570,6 +1575,7 @@ protected function filterDebugData($data) /** * Parse track details response from Fedex + * * @param \stdClass $trackInfo * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -1640,6 +1646,7 @@ private function processTrackingDetails(\stdClass $trackInfo) /** * Parse delivery datetime from tracking details + * * @param \stdClass $trackInfo * @return \Datetime|null */ @@ -1656,8 +1663,7 @@ private function getDeliveryDateTime(\stdClass $trackInfo) } /** - * Get delivery address details in string representation - * Return City, State, Country Code + * Get delivery address details in string representation Return City, State, Country Code * * @param \stdClass $address * @return \Magento\Framework\Phrase|string @@ -1719,6 +1725,7 @@ private function processTrackDetailsEvents(array $events) /** * Append error message to rate result instance + * * @param string $trackingValue * @param string $errorMessage */ @@ -1760,8 +1767,7 @@ private function parseDate($timestamp) } /** - * Defines payment type by request. - * Two values are available: RECIPIENT or SENDER. + * Defines payment type by request. Two values are available: RECIPIENT or SENDER. * * @param DataObject $request * @return string diff --git a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php index dbcb62907736c..0b698afea1de3 100644 --- a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php +++ b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php @@ -65,7 +65,7 @@ public function create(VaultPaymentInterface $paymentMethod, int $storeId): Inte /** * Reads value from config. * - * @param $config + * @param array $config * @param string $field * @param string $default * @return string diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 68090f12e99be..5cd5bf7f02bd8 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -82,7 +82,9 @@ public function __construct( } /** - * {@inheritdoc} + * Get data + * + * @return mixed */ public function getData() { @@ -95,7 +97,10 @@ public function getData() } /** - * {@inheritdoc} + * Get Meta + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException */ public function getMeta() { @@ -107,7 +112,9 @@ public function getMeta() } /** - * {@inheritdoc} + * Get Data Provider name + * + * @return string */ public function getName() { @@ -115,7 +122,9 @@ public function getName() } /** - * {@inheritdoc} + * Get config data + * + * @return mixed */ public function getConfigData() { @@ -123,7 +132,11 @@ public function getConfigData() } /** - * {@inheritdoc} + * Set config data + * + * @param mixed $config + * + * @return bool */ public function setConfigData($config) { @@ -133,7 +146,12 @@ public function setConfigData($config) } /** - * {@inheritdoc} + * Get Field Meta Info + * + * @param string $fieldSetName + * @param string $fieldName + * + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldMetaInfo($fieldSetName, $fieldName) @@ -142,7 +160,11 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) } /** - * {@inheritdoc} + * Get Field Set Meta Info + * + * @param string $fieldSetName + * + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldSetMetaInfo($fieldSetName) @@ -151,7 +173,11 @@ public function getFieldSetMetaInfo($fieldSetName) } /** - * {@inheritdoc} + * Get Fields Meta Info + * + * @param string $fieldSetName + * + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldsMetaInfo($fieldSetName) @@ -160,7 +186,9 @@ public function getFieldsMetaInfo($fieldSetName) } /** - * {@inheritdoc} + * Get Primary Field Name + * + * @return string */ public function getPrimaryFieldName() { @@ -168,7 +196,9 @@ public function getPrimaryFieldName() } /** - * {@inheritdoc} + * Get Request Field Name + * + * @return string */ public function getRequestFieldName() { @@ -176,7 +206,11 @@ public function getRequestFieldName() } /** - * {@inheritdoc} + * Add Filter + * + * @param \Magento\Framework\Api\Filter $filter + * + * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function addFilter(\Magento\Framework\Api\Filter $filter) @@ -184,7 +218,12 @@ public function addFilter(\Magento\Framework\Api\Filter $filter) } /** - * {@inheritdoc} + * Add Order + * + * @param string $field + * @param string $direction + * + * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function addOrder($field, $direction) @@ -192,7 +231,12 @@ public function addOrder($field, $direction) } /** - * {@inheritdoc} + * Set Limit + * + * @param int $offset + * @param int $size + * + * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function setLimit($offset, $size) @@ -200,7 +244,9 @@ public function setLimit($offset, $size) } /** - * {@inheritdoc} + * Get Search Criteria + * + * @return SearchCriteriaInterface */ public function getSearchCriteria() { @@ -208,7 +254,9 @@ public function getSearchCriteria() } /** - * {@inheritdoc} + * Get Search Result + * + * @return SearchResultInterface */ public function getSearchResult() { diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index eab671fdb85da..a525d62662d03 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -173,7 +173,7 @@ protected function implodeStreetValue($value) * Enforce format of the street field * * @param array|string $key - * @param null $value + * @param array|string $value * @return \Magento\Framework\DataObject */ public function setData($key, $value = null) @@ -508,7 +508,11 @@ public function getVatRequestSuccess() } /** - * {@inheritdoc} + * Set Parent ID + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setParentId($id) { @@ -516,7 +520,11 @@ public function setParentId($id) } /** - * {@inheritdoc} + * Sets the country address ID for the order address. + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setCustomerAddressId($id) { @@ -524,7 +532,11 @@ public function setCustomerAddressId($id) } /** - * {@inheritdoc} + * Sets the region ID for the order address. + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setRegionId($id) { @@ -532,7 +544,11 @@ public function setRegionId($id) } /** - * {@inheritdoc} + * Sets the customer ID for the order address. + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setStreet($street) { @@ -540,7 +556,11 @@ public function setStreet($street) } /** - * {@inheritdoc} + * Sets the fax number for the order address. + * + * @param string $fax + * + * @return \Magento\Framework\DataObject|Address */ public function setCustomerId($id) { @@ -548,7 +568,11 @@ public function setCustomerId($id) } /** - * {@inheritdoc} + * Sets the region for the order address. + * + * @param string $region + * + * @return \Magento\Framework\DataObject|Address */ public function setFax($fax) { @@ -556,7 +580,11 @@ public function setFax($fax) } /** - * {@inheritdoc} + * Sets the postal code for the order address. + * + * @param string $postcode + * + * @return \Magento\Framework\DataObject|Address */ public function setRegion($region) { @@ -564,7 +592,11 @@ public function setRegion($region) } /** - * {@inheritdoc} + * Sets the last name for the order address. + * + * @param string $lastname + * + * @return \Magento\Framework\DataObject|Address */ public function setPostcode($postcode) { @@ -572,7 +604,11 @@ public function setPostcode($postcode) } /** - * {@inheritdoc} + * Sets the street values, if any, for the order address. + * + * @param string|string[] $street + * + * @return \Magento\Framework\DataObject|Address */ public function setLastname($lastname) { @@ -580,7 +616,11 @@ public function setLastname($lastname) } /** - * {@inheritdoc} + * Sets the city for the order address. + * + * @param string $city + * + * @return \Magento\Framework\DataObject|Address */ public function setCity($city) { @@ -588,7 +628,11 @@ public function setCity($city) } /** - * {@inheritdoc} + * Sets the email address for the order address. + * + * @param string $email + * + * @return \Magento\Framework\DataObject|Address */ public function setEmail($email) { @@ -596,7 +640,11 @@ public function setEmail($email) } /** - * {@inheritdoc} + * Sets the telephone number for the order address. + * + * @param string $telephone + * + * @return \Magento\Framework\DataObject|Address */ public function setTelephone($telephone) { @@ -604,7 +652,11 @@ public function setTelephone($telephone) } /** - * {@inheritdoc} + * Sets the country ID for the order address. + * + * @param string $id + * + * @return \Magento\Framework\DataObject|Address */ public function setCountryId($id) { @@ -612,7 +664,11 @@ public function setCountryId($id) } /** - * {@inheritdoc} + * Sets the first name for the order address. + * + * @param string $firstname + * + * @return \Magento\Framework\DataObject|Address */ public function setFirstname($firstname) { @@ -620,7 +676,11 @@ public function setFirstname($firstname) } /** - * {@inheritdoc} + * Sets the address type for the order address. + * + * @param string $addressType + * + * @return \Magento\Framework\DataObject|Address */ public function setAddressType($addressType) { @@ -628,7 +688,11 @@ public function setAddressType($addressType) } /** - * {@inheritdoc} + * Sets the prefix for the order address. + * + * @param string $prefix + * + * @return \Magento\Framework\DataObject|Address */ public function setPrefix($prefix) { @@ -636,7 +700,11 @@ public function setPrefix($prefix) } /** - * {@inheritdoc} + * Sets the middle name for the order address. + * + * @param string $middlename + * + * @return \Magento\Framework\DataObject|Address */ public function setMiddlename($middlename) { @@ -644,7 +712,11 @@ public function setMiddlename($middlename) } /** - * {@inheritdoc} + * Sets the suffix for the order address. + * + * @param string $suffix + * + * @return \Magento\Framework\DataObject|Address */ public function setSuffix($suffix) { @@ -652,7 +724,11 @@ public function setSuffix($suffix) } /** - * {@inheritdoc} + * Sets the company for the order address. + * + * @param string $company + * + * @return \Magento\Framework\DataObject|Address */ public function setCompany($company) { @@ -660,7 +736,11 @@ public function setCompany($company) } /** - * {@inheritdoc} + * Sets the VAT ID for the order address. + * + * @param string $id + * + * @return \Magento\Framework\DataObject|Address */ public function setVatId($id) { @@ -668,7 +748,11 @@ public function setVatId($id) } /** - * {@inheritdoc} + * Sets the VAT-is-valid flag value for the order address. + * + * @param int $vatIsValid + * + * @return \Magento\Framework\DataObject|Address */ public function setVatIsValid($vatIsValid) { @@ -676,7 +760,11 @@ public function setVatIsValid($vatIsValid) } /** - * {@inheritdoc} + * Sets the VAT request ID for the order address. + * + * @param string $id + * + * @return \Magento\Framework\DataObject|Address */ public function setVatRequestId($id) { @@ -684,7 +772,11 @@ public function setVatRequestId($id) } /** - * {@inheritdoc} + * Set region code + * + * @param string $regionCode + * + * @return \Magento\Framework\DataObject|Address */ public function setRegionCode($regionCode) { @@ -692,7 +784,11 @@ public function setRegionCode($regionCode) } /** - * {@inheritdoc} + * Sets the VAT request date for the order address. + * + * @param string $vatRequestDate + * + * @return \Magento\Framework\DataObject|Address */ public function setVatRequestDate($vatRequestDate) { @@ -700,7 +796,11 @@ public function setVatRequestDate($vatRequestDate) } /** - * {@inheritdoc} + * Sets the VAT-request-success flag value for the order address. + * + * @param int $vatRequestSuccess + * + * @return \Magento\Framework\DataObject|Address */ public function setVatRequestSuccess($vatRequestSuccess) { @@ -708,7 +808,7 @@ public function setVatRequestSuccess($vatRequestSuccess) } /** - * {@inheritdoc} + * Retrieve existing extension attributes object or create a new one. * * @return \Magento\Sales\Api\Data\OrderAddressExtensionInterface|null */ @@ -718,7 +818,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * Set an extension attributes object. * * @param \Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes * @return $this diff --git a/app/code/Magento/Sales/Model/Order/Payment/Info.php b/app/code/Magento/Sales/Model/Order/Payment/Info.php index 0a6b257846bfa..fee846fe6a62c 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Info.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Info.php @@ -11,8 +11,8 @@ use Magento\Payment\Model\InfoInterface; /** - * * Payment information model + * * @api * @since 100.0.2 */ @@ -41,7 +41,7 @@ class Info extends AbstractModel implements InfoInterface * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory - * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory, + * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory * @param \Magento\Payment\Helper\Data $paymentData * @param \Magento\Framework\Encryption\EncryptorInterface $encryptor * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource @@ -219,8 +219,7 @@ public function hasAdditionalInformation($key = null) } /** - * Initialize additional information container with data from model - * if property empty + * Initialize additional information container with data from model if property empty * * @return void */ diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 96312e7e0192b..07d9dfc851cf6 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -132,10 +132,12 @@ class Transaction extends AbstractModel implements TransactionInterface * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory * @param AttributeValueFactory $customAttributeFactory * @param \Magento\Sales\Model\OrderFactory $orderFactory + * @param \Magento\Sales\Api\OrderPaymentRepositoryInterface $orderPaymentRepository + * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository * @param \Magento\Framework\Stdlib\DateTime\DateTimeFactory $dateFactory * @param TransactionFactory $transactionFactory - * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource - * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection + * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource + * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -193,8 +195,7 @@ public function setTxnId($txnId) } /** - * Parent transaction ID setter - * Can set the transaction id as well + * Parent transaction ID setter Can set the transaction id as well * * @param string $parentTxnId * @param string $txnId @@ -229,8 +230,7 @@ public function setTxnType($txnType) } /** - * Parent transaction getter - * May attempt to load it. + * Parent transaction getter. May attempt to load it. * * @param bool $shouldLoad * @return bool|\Magento\Sales\Model\Order\Payment\Transaction @@ -366,8 +366,7 @@ public function closeAuthorization($shouldSave = true, $dryRun = false) } /** - * Close a capture transaction - * Logic is similar to closeAuthorization(), but for a capture transaction + * Close a capture transaction. Logic is similar to closeAuthorization(), but for a capture transaction * * @param bool $shouldSave * @return bool|\Magento\Sales\Model\Order\Payment\Transaction @@ -395,6 +394,7 @@ public function closeCapture($shouldSave = true) /** * Check whether authorization in current hierarchy can be voided completely + * * Basically checks whether the authorization exists and it is not affected by a capture or void * * @return bool @@ -536,6 +536,7 @@ public function close($shouldSave = true) /** * Order ID getter + * * Attempts to get ID from set order payment object, if any, or from data by key 'order_id' * * @return int|null @@ -572,6 +573,7 @@ public function getOrder() /** * Set order instance for transaction depends on transaction behavior + * * If $order equals to true, method isn't loading new order instance. * * @param \Magento\Sales\Model\Order|null|boolean $order @@ -695,7 +697,6 @@ protected function _loadChildren() /** * Check whether this transaction is voided * - * TODO: implement that there should be only one void per authorization * @return bool */ protected function _isVoided() @@ -805,7 +806,6 @@ protected function _verifyTxnId($txnId) /** * Make sure this object is a valid transaction - * TODO for more restriction we can check for data consistency * * @return void * @throws \Magento\Framework\Exception\LocalizedException @@ -833,7 +833,11 @@ public function getTransactionId() } /** - * {@inheritdoc} + * Set Transaction ID + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setTransactionId($id) { @@ -942,7 +946,11 @@ public function getCreatedAt() } /** - * {@inheritdoc} + * Gets an array of child transactions for the transaction. + * + * @param string $createdAt + * + * @return TransactionInterface|Transaction */ public function setCreatedAt($createdAt) { @@ -950,7 +958,11 @@ public function setCreatedAt($createdAt) } /** - * {@inheritdoc} + * Sets the parent ID for the transaction. + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setParentId($id) { @@ -958,7 +970,11 @@ public function setParentId($id) } /** - * {@inheritdoc} + * Sets the order ID for the transaction. + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setOrderId($id) { @@ -966,7 +982,11 @@ public function setOrderId($id) } /** - * {@inheritdoc} + * Sets the payment ID for the transaction. + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setPaymentId($id) { @@ -974,7 +994,11 @@ public function setPaymentId($id) } /** - * {@inheritdoc} + * Sets the parent transaction business ID for the transaction. + * + * @param string $id + * + * @return TransactionInterface|Transaction */ public function setIsClosed($isClosed) { @@ -982,7 +1006,7 @@ public function setIsClosed($isClosed) } /** - * {@inheritdoc} + * Retrieve existing extension attributes object or create a new one. * * @return \Magento\Sales\Api\Data\TransactionExtensionInterface|null */ @@ -992,7 +1016,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * Set an extension attributes object. * * @param \Magento\Sales\Api\Data\TransactionExtensionInterface $extensionAttributes * @return $this diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php index 844258f80a284..27047ae46bf1f 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php @@ -216,6 +216,7 @@ public function getTrackingInfo($tracking) /** * Check if carrier has shipping tracking option available + * * All \Magento\Usa carriers have shipping tracking option available * * @return boolean @@ -399,8 +400,8 @@ protected function _getQuotesCacheKey($requestParams) /** * Checks whether some request to rates have already been done, so we have cache for it - * Used to reduce number of same requests done to carrier service during one session * + * Used to reduce number of same requests done to carrier service during one session * Returns cached response or null * * @param string|array $requestParams @@ -443,8 +444,7 @@ protected function _prepareServiceName($name) } /** - * Prepare shipment request. - * Validate and correct request information + * Prepare shipment request. Validate and correct request information * * @param \Magento\Framework\DataObject $request * @return void @@ -558,8 +558,7 @@ public function returnOfShipment($request) } /** - * For multi package shipments. Delete requested shipments if the current shipment - * request is failed + * For multi package shipments. Delete requested shipments if the current shipment. Request is failed * * @param array $data * @return bool @@ -625,6 +624,8 @@ public function isGirthAllowed($countyDest = null, $carrierMethodCode = null) } /** + * Set Raw Request + * * @param \Magento\Framework\DataObject|null $request * @return $this * @api @@ -680,6 +681,7 @@ public function parseXml($xmlContent, $customSimplexml = 'SimpleXMLElement') /** * Checks if shipping method can collect rates + * * @return bool */ public function canCollectRates() @@ -689,6 +691,7 @@ public function canCollectRates() /** * Debug errors if showmethod is unset + * * @param Error $errors * * @return void diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index d55bf0b5e1cd0..e64f5f21bd5eb 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -412,6 +412,8 @@ public function __construct( } /** + * Magic method called during class serialization + * * @return string[] */ public function __sleep() @@ -792,6 +794,8 @@ public function isFrontUrlSecure() } /** + * Return is URL should be secure + * * @return bool */ public function isUrlSecure() @@ -1363,6 +1367,8 @@ public function getIdentities() } /** + * Return Store Path + * * @return string */ public function getStorePath() @@ -1372,6 +1378,8 @@ public function getStorePath() } /** + * Get scope type + * * {@inheritdoc} * @since 100.1.0 */ @@ -1381,6 +1389,8 @@ public function getScopeType() } /** + * Get Scope Type Name + * * {@inheritdoc} * @since 100.1.0 */ @@ -1390,6 +1400,8 @@ public function getScopeTypeName() } /** + * Retrieve existing extension attributes object or create a new one. + * * {@inheritdoc} */ public function getExtensionAttributes() @@ -1398,6 +1410,8 @@ public function getExtensionAttributes() } /** + * Set an extension attributes object. + * * @param \Magento\Store\Api\Data\StoreExtensionInterface $extensionAttributes * @return $this */ diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index 8817a947f835e..4333b2cf4fe60 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -48,9 +48,9 @@ protected function _construct() /** * Retrieve layout updates by handle * - * @param string $handle + * @param string $handle * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface $store + * @param \Magento\Framework\App\ScopeInterface store * * @return string * @throws \Magento\Framework\Exception\LocalizedException From 7aeb3be0530da6e3641b432ec2a5a5d99d43635c Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Sun, 23 Sep 2018 12:24:03 +0300 Subject: [PATCH 0081/1158] fix tests --- .../DataProvider/NotificationDataProvider.php | 2 +- .../Magento/Sales/Model/Order/Address.php | 24 +++++++++---------- .../Sales/Model/Order/Payment/Transaction.php | 4 ++-- app/code/Magento/Store/Model/Store.php | 6 ++--- .../Model/ResourceModel/Layout/Update.php | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 5cd5bf7f02bd8..26e698b67545b 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -147,7 +147,7 @@ public function setConfigData($config) /** * Get Field Meta Info - * + * * @param string $fieldSetName * @param string $fieldName * diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index a525d62662d03..8a4406e17a7e6 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -544,9 +544,9 @@ public function setRegionId($id) } /** - * Sets the customer ID for the order address. + * Sets the street values, if any, for the order address. * - * @param int $id + * @param string|string[] $street * * @return \Magento\Framework\DataObject|Address */ @@ -556,9 +556,9 @@ public function setStreet($street) } /** - * Sets the fax number for the order address. + * Sets the customer ID for the order address. * - * @param string $fax + * @param int $id * * @return \Magento\Framework\DataObject|Address */ @@ -568,9 +568,9 @@ public function setCustomerId($id) } /** - * Sets the region for the order address. + * Sets the fax number for the order address. * - * @param string $region + * @param string $fax * * @return \Magento\Framework\DataObject|Address */ @@ -580,9 +580,9 @@ public function setFax($fax) } /** - * Sets the postal code for the order address. + * Sets the region for the order address. * - * @param string $postcode + * @param string $region * * @return \Magento\Framework\DataObject|Address */ @@ -592,9 +592,9 @@ public function setRegion($region) } /** - * Sets the last name for the order address. + * Sets the postal code for the order address. * - * @param string $lastname + * @param string $postcode * * @return \Magento\Framework\DataObject|Address */ @@ -604,9 +604,9 @@ public function setPostcode($postcode) } /** - * Sets the street values, if any, for the order address. + * Sets the last name for the order address. * - * @param string|string[] $street + * @param string $lastname * * @return \Magento\Framework\DataObject|Address */ diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 07d9dfc851cf6..d1a8e99a98027 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -994,9 +994,9 @@ public function setPaymentId($id) } /** - * Sets the parent transaction business ID for the transaction. + * Sets the value of the is-closed flag for the transaction. * - * @param string $id + * @param int $isClosed * * @return TransactionInterface|Transaction */ diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index e64f5f21bd5eb..31d2b7bf30327 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1380,7 +1380,7 @@ public function getStorePath() /** * Get scope type * - * {@inheritdoc} + * @return string * @since 100.1.0 */ public function getScopeType() @@ -1391,7 +1391,7 @@ public function getScopeType() /** * Get Scope Type Name * - * {@inheritdoc} + * @return string * @since 100.1.0 */ public function getScopeTypeName() @@ -1402,7 +1402,7 @@ public function getScopeTypeName() /** * Retrieve existing extension attributes object or create a new one. * - * {@inheritdoc} + * @return \Magento\Store\Api\Data\StoreExtensionInterface|null */ public function getExtensionAttributes() { diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index 4333b2cf4fe60..6c0aef9e67186 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -50,7 +50,7 @@ protected function _construct() * * @param string $handle * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface store + * @param \Magento\Framework\App\ScopeInterface $store * * @return string * @throws \Magento\Framework\Exception\LocalizedException From 18f78d5c5b1a760813647b794e5365dfe885367e Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Mon, 24 Sep 2018 15:26:43 +0300 Subject: [PATCH 0082/1158] MAGETWO-91725: Reward Points Balance Update Emails are not being sent when balance change initiated by store front - Fixed an issue with incorrect work of 'Subscribe for Balance Updates' functionality; --- .../Model/Metadata/CustomerMetadata.php | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php b/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php index 7ed806e657e82..7e8f0b9236fe9 100644 --- a/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php +++ b/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php @@ -46,7 +46,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getAttributes($formCode) { @@ -67,7 +67,7 @@ public function getAttributes($formCode) } /** - * {@inheritdoc} + * @inheritdoc */ public function getAttributeMetadata($attributeCode) { @@ -92,7 +92,7 @@ public function getAttributeMetadata($attributeCode) } /** - * {@inheritdoc} + * @inheritdoc */ public function getAllAttributesMetadata() { @@ -116,7 +116,7 @@ public function getAllAttributesMetadata() } /** - * {@inheritdoc} + * @inheritdoc */ public function getCustomAttributesMetadata($dataObjectClassName = self::DATA_INTERFACE_NAME) { @@ -134,13 +134,27 @@ public function getCustomAttributesMetadata($dataObjectClassName = self::DATA_IN $isDataObjectMethod = isset($this->customerDataObjectMethods['get' . $camelCaseKey]) || isset($this->customerDataObjectMethods['is' . $camelCaseKey]); - /** Even though disable_auto_group_change is system attribute, it should be available to the clients */ if (!$isDataObjectMethod - && (!$attributeMetadata->isSystem() || $attributeCode == 'disable_auto_group_change') + && (!$attributeMetadata->isSystem() + || in_array($attributeCode, $this->getAllowedSystemAttributesList()) + ) ) { $customAttributes[] = $attributeMetadata; } } return $customAttributes; } + + /** + * Get list of system attributes which should be available to the clients + * + * @return array + */ + private function getAllowedSystemAttributesList() + { + return [ + 'disable_auto_group_change', + 'reward_update_notification' + ]; + } } From aef18a56e212eb0f55c5393c5a814b6bb15c9510 Mon Sep 17 00:00:00 2001 From: Aleksey Tsoy <aleksey_tsoy@epam.com> Date: Mon, 24 Sep 2018 19:04:00 +0600 Subject: [PATCH 0083/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Added automated test --- .../StorefrontCategoryActionGroup.xml | 15 +++ .../Mftf/Data/CatalogStorefrontConfigData.xml | 41 ++++++ .../Metadata/catalog_configuration-meta.xml | 118 ++++++++++++++++++ .../Section/StorefrontCategoryMainSection.xml | 3 + ...orefrontRememberCategoryPaginationTest.xml | 68 ++++++++++ 5 files changed, 245 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Data/CatalogStorefrontConfigData.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_configuration-meta.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/StorefrontRememberCategoryPaginationTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml index c980c43b8f3af..e215aa81b3384 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml @@ -21,6 +21,21 @@ <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> + <actionGroup name="VerifyCategoryPageParameters"> + <arguments> + <argument name="category"/> + <argument name="mode" type="string"/> + <argument name="numOfProductsPerPage" type="string"/> + <argument name="sortBy" type="string" defaultValue="position"/> + </arguments> + <seeInCurrentUrl url="/{{category.custom_attributes[url_key]}}.html" stepKey="checkUrl"/> + <seeInTitle userInput="{{category.name}}" stepKey="assertCategoryNameInTitle"/> + <see userInput="{{category.name}}" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="assertCategoryName"/> + <see userInput="{{mode}}" selector="{{StorefrontCategoryMainSection.modeGridIsActive}}" stepKey="assertViewMode"/> + <see userInput="{{numOfProductsPerPage}}" selector="{{StorefrontCategoryMainSection.perPage}}" stepKey="assertNumberOfProductsPerPage"/> + <see userInput="{{sortBy}}" selector="{{StorefrontCategoryMainSection.sortedBy}}" stepKey="assertSortedBy"/> + </actionGroup> + <!-- Check the category page --> <actionGroup name="StorefrontCheckCategoryActionGroup"> <arguments> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CatalogStorefrontConfigData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogStorefrontConfigData.xml new file mode 100644 index 0000000000000..d8ec84013d93b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogStorefrontConfigData.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="RememberPaginationCatalogStorefrontConfig" type="catalog_storefront_config"> + <requiredEntity type="grid_per_page_values">GridPerPageValues</requiredEntity> + <requiredEntity type="remember_pagination">RememberCategoryPagination</requiredEntity> + </entity> + + <entity name="GridPerPageValues" type="grid_per_page_values"> + <data key="value">9,12,20,24</data> + </entity> + + <entity name="RememberCategoryPagination" type="remember_pagination"> + <data key="value">1</data> + </entity> + + <entity name="DefaultCatalogStorefrontConfiguration" type="default_catalog_storefront_config"> + <requiredEntity type="catalogStorefrontFlagZero">DefaultCatalogStorefrontFlagZero</requiredEntity> + <data key="list_allow_all">DefaultListAllowAll</data> + <data key="flat_catalog_product">DefaultFlatCatalogProduct</data> + </entity> + + <entity name="DefaultCatalogStorefrontFlagZero" type="catalogStorefrontFlagZero"> + <data key="value">0</data> + </entity> + + <entity name="DefaultListAllowAll" type="list_allow_all"> + <data key="value">0</data> + </entity> + + <entity name="DefaultFlatCatalogProduct" type="flat_catalog_product"> + <data key="value">0</data> + </entity> +</entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_configuration-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_configuration-meta.xml new file mode 100644 index 0000000000000..b1f2b43220b36 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_configuration-meta.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CatalogStorefrontConfiguration" dataType="catalog_storefront_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/catalog/" method="POST"> + <object key="groups" dataType="catalog_storefront_config"> + <object key="frontend" dataType="catalog_storefront_config"> + <object key="fields" dataType="catalog_storefront_config"> + <object key="list_mode" dataType="list_mode"> + <field key="value">string</field> + </object> + <object key="grid_per_page_values" dataType="grid_per_page_values"> + <field key="value">string</field> + </object> + <object key="grid_per_page" dataType="grid_per_page"> + <field key="value">string</field> + </object> + <object key="list_per_page_values" dataType="list_per_page_values"> + <field key="value">string</field> + </object> + <object key="list_per_page" dataType="list_per_page"> + <field key="value">string</field> + </object> + <object key="default_sort_by" dataType="default_sort_by"> + <field key="value">string</field> + </object> + <object key="list_allow_all" dataType="list_allow_all"> + <field key="value">integer</field> + </object> + <object key="remember_pagination" dataType="remember_pagination"> + <field key="value">integer</field> + </object> + <object key="flat_catalog_category" dataType="flat_catalog_category"> + <field key="value">integer</field> + </object> + <object key="flat_catalog_product" dataType="flat_catalog_product"> + <field key="value">integer</field> + </object> + <object key="swatches_per_product" dataType="swatches_per_product"> + <field key="value">string</field> + </object> + <object key="show_swatches_in_product_list" dataType="show_swatches_in_product_list"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </operation> + + <operation name="DefaultCatalogStorefrontConfiguration" dataType="default_catalog_storefront_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/catalog/" method="POST"> + <object key="groups" dataType="default_catalog_storefront_config"> + <object key="frontend" dataType="default_catalog_storefront_config"> + <object key="fields" dataType="default_catalog_storefront_config"> + <object key="list_mode" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="grid_per_page_values" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="grid_per_page" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="list_per_page_values" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="list_per_page" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="default_sort_by" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="remember_pagination" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="flat_catalog_category" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="swatches_per_product" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="show_swatches_in_product_list" dataType="default_catalog_storefront_config"> + <object key="inherit" dataType="catalogStorefrontFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="list_allow_all" dataType="list_allow_all"> + <field key="value">integer</field> + </object> + <object key="flat_catalog_product" dataType="flat_catalog_product"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml index d484abf2069ff..03566be55ad2f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml @@ -9,6 +9,9 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="StorefrontCategoryMainSection"> + <element name="perPage" type="select" selector="//*[@id='authenticationPopup']/following-sibling::div[3]//*[@id='limiter']"/> + <element name="sortedBy" type="select" selector="//*[@id='authenticationPopup']/following-sibling::div[1]//*[@id='sorter']"/> + <element name="modeGridIsActive" type="text" selector="//*[@id='authenticationPopup']/following-sibling::div[1]//*[@class='modes']/strong[@class='modes-mode active mode-grid']/span"/> <element name="modeListButton" type="button" selector="#mode-list"/> <element name="CategoryTitle" type="text" selector="#page-title-heading span"/> <element name="ProductItemInfo" type="button" selector=".product-item-info"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontRememberCategoryPaginationTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontRememberCategoryPaginationTest.xml new file mode 100644 index 0000000000000..0ed61b8636c4f --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontRememberCategoryPaginationTest.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontRememberCategoryPaginationTest"> + <annotations> + <title value="Verify that Number of Products per page retained when visiting a different category"/> + <stories value="MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category"/> + <description value="Verify that Number of Products per page retained when visiting a different category"/> + <features value="Catalog"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-94210"/> + <group value="Catalog"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="defaultCategory1"/> + <createData entity="SimpleProduct" stepKey="simpleProduct1"> + <requiredEntity createDataKey="defaultCategory1"/> + </createData> + + <createData entity="_defaultCategory" stepKey="defaultCategory2"/> + <createData entity="SimpleProduct" stepKey="simpleProduct2"> + <requiredEntity createDataKey="defaultCategory2"/> + </createData> + + <createData entity="RememberPaginationCatalogStorefrontConfig" stepKey="setRememberPaginationCatalogStorefrontConfig"/> + </before> + + <actionGroup ref="GoToStorefrontCategoryPageByParameters" stepKey="GoToStorefrontCategory1Page"> + <argument name="category" value="$$defaultCategory1.custom_attributes[url_key]$$"/> + <argument name="mode" value="grid"/> + <argument name="numOfProductsPerPage" value="12"/> + </actionGroup> + + <actionGroup ref="VerifyCategoryPageParameters" stepKey="verifyCategory1PageParameters"> + <argument name="category" value="$$defaultCategory1$$"/> + <argument name="mode" value="grid"/> + <argument name="numOfProductsPerPage" value="12"/> + </actionGroup> + + <amOnPage url="{{StorefrontCategoryPage.url($$defaultCategory2.name$$)}}" stepKey="navigateToCategory2Page"/> + <waitForPageLoad stepKey="waitForCategory2PageToLoad"/> + + <actionGroup ref="VerifyCategoryPageParameters" stepKey="verifyCategory2PageParameters"> + <argument name="category" value="$$defaultCategory2$$"/> + <argument name="mode" value="grid"/> + <argument name="numOfProductsPerPage" value="12"/> + </actionGroup> + + <after> + <createData entity="DefaultCatalogStorefrontConfiguration" stepKey="setDefaultCatalogStorefrontConfiguration"/> + + <deleteData createDataKey="simpleProduct1" stepKey="deleteProduct1"/> + <deleteData createDataKey="defaultCategory1" stepKey="deleteCategory1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteProduct2"/> + <deleteData createDataKey="defaultCategory2" stepKey="deleteCategory2"/> + + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + </after> + </test> +</tests> From 160f0879e39e39a6baa48723c05255c0fc37c860 Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets <yauhen_lyskavets@epam.com> Date: Mon, 24 Sep 2018 16:48:01 +0300 Subject: [PATCH 0084/1158] MAGETWO-91707: [Sigma Beauty]Cannot pause Youtube video in IE 11 - Fix added --- lib/web/fotorama/fotorama.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/web/fotorama/fotorama.js b/lib/web/fotorama/fotorama.js index 89cb315b0d2c4..4bfa2f12d5248 100644 --- a/lib/web/fotorama/fotorama.js +++ b/lib/web/fotorama/fotorama.js @@ -2487,11 +2487,11 @@ fotoramaVersion = '4.6.4'; .append($videoPlay.clone()); // This solves tabbing problems - addFocus(frame, function () { + addFocus(frame, function (e) { setTimeout(function () { lockScroll($stage); }, 0); - clickToShow({index: frameData.eq, user: true}); + clickToShow({index: frameData.eq, user: true}, e); }); $stageFrame = $stageFrame.add($frame); @@ -3040,7 +3040,10 @@ fotoramaVersion = '4.6.4'; return time; } - that.showStage = function (silent, options, time) { + that.showStage = function (silent, options, time, e) { + if (e !== undefined && e.target.tagName == 'IFRAME') { + return; + } unloadVideo($videoPlaying, activeFrame.i !== data[normalizeIndex(repositionIndex)].i); frameDraw(activeIndexes, 'stage'); stageFramePosition(SLOW ? [dirtyIndex] : [dirtyIndex, getPrevIndex(dirtyIndex), getNextIndex(dirtyIndex)]); @@ -3128,7 +3131,7 @@ fotoramaVersion = '4.6.4'; } }; - that.show = function (options) { + that.show = function (options, e) { that.longPress.singlePressInProgress = true; var index = calcActiveIndex(options); @@ -3139,7 +3142,7 @@ fotoramaVersion = '4.6.4'; var silent = _activeFrame === activeFrame && !options.user; - that.showStage(silent, options, time); + that.showStage(silent, options, time, e); that.showNav(silent, options, time); showedFLAG = typeof lastActiveIndex !== 'undefined' && lastActiveIndex !== activeIndex; @@ -3499,7 +3502,7 @@ fotoramaVersion = '4.6.4'; $stage.on('mousemove', stageCursor); - function clickToShow(showOptions) { + function clickToShow(showOptions, e) { clearTimeout(clickToShow.t); if (opts.clicktransition && opts.clicktransition !== opts.transition) { @@ -3516,7 +3519,7 @@ fotoramaVersion = '4.6.4'; }, 10); }, 0); } else { - that.show(showOptions); + that.show(showOptions, e); } } From b4bb58cfd3e0c33c96b4100ea84ba30197ad7c23 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Mon, 24 Sep 2018 16:59:40 +0300 Subject: [PATCH 0085/1158] MAGETWO-91657: Advanced pricing the bulk discounts by percentage returns error when set - Added new validation rule for percentage value; --- .../Product/Form/Modifier/TierPrice.php | 4 +--- .../view/base/web/js/lib/validation/rules.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php index 5f8d7fcf9049a..1f0da62f61056 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php @@ -154,9 +154,7 @@ private function getUpdatedTierPriceStructure(array $priceMeta) 'addbefore' => '%', 'validation' => [ 'required-entry' => true, - 'validate-number' => true, - 'validate-greater-than-zero' => true, - 'less-than-equals-to' => 100 + 'validate-positive-percent-decimal' => true ], 'visible' => $firstOption && $firstOption['value'] == ProductPriceOptionsInterface::VALUE_PERCENT, diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js index 74f696f3f2a24..1c647bed2ea7b 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js @@ -686,6 +686,24 @@ define([ }, $.mage.__('The value is not within the specified range.') ], + 'validate-positive-percent-decimal': [ + function (value) { + var numValue; + + if (utils.isEmptyNoTrim(value) || !/^\s*-?\d*(\.\d*)?\s*$/.test(value)) { + return false; + } + + numValue = utils.parseNumber(value); + + if (isNaN(numValue)) { + return false; + } + + return utils.isBetween(numValue, 0.01, 100); + }, + $.mage.__('Please enter a valid percentage discount value greater than 0.') + ], 'validate-digits': [ function (value) { return utils.isEmptyNoTrim(value) || !/[^\d]/.test(value); From 68933c1b128f09b74298f81822879e2bee63d68a Mon Sep 17 00:00:00 2001 From: Mikalai Shostka <mikalai_shostka@epam.com> Date: Mon, 24 Sep 2018 17:35:47 +0300 Subject: [PATCH 0086/1158] MAGETWO-70303: [GITHUB] Anchor categories are showing products of disabled subcategories #9002 - Change index table and temporary table --- .../Category/Product/AbstractAction.php | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index 6a499883ac723..d312b78e74059 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -499,7 +499,7 @@ protected function createAnchorSelect(Store $store) 'cc2.parent_id = cc.entity_id AND cc.entity_id NOT IN (' . implode( ',', $rootCatIds - ) . ')', + ) . ') AND cc2.store_id = ' . $store->getId(), [] )->joinInner( ['ccp' => $this->getTable('catalog_category_product')], @@ -586,6 +586,8 @@ protected function createAnchorSelect(Store $store) } /** + * Get temporary table name + * * Get temporary table name for concurrent indexing in persistent connection * Temp table name is NOT shared between action instances and each action has it's own temp tree index * @@ -629,6 +631,12 @@ protected function makeTempCategoryTreeIndex() null, ['nullable' => false, 'unsigned' => true] ); + $temporaryTable->addColumn( + 'store_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['nullable' => false, 'unsigned' => true] + ); // Each entry will be unique. $temporaryTable->addIndex( 'idx_primary', @@ -642,6 +650,11 @@ protected function makeTempCategoryTreeIndex() ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] ); + $temporaryTable->addIndex( + 'store_id', + ['store_id'], + ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] + ); // Drop the temporary table in case it already exists on this (persistent?) connection. $this->connection->dropTemporaryTable($temporaryName); $this->connection->createTemporaryTable($temporaryTable); @@ -659,11 +672,23 @@ protected function makeTempCategoryTreeIndex() */ protected function fillTempCategoryTreeIndex($temporaryName) { + $isActiveAttributeId = $this->config->getAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'is_active' + )->getId(); + $categoryMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\CategoryInterface::class); + $categoryLinkField = $categoryMetadata->getLinkField(); $selects = $this->prepareSelectsByRange( $this->connection->select() ->from( ['c' => $this->getTable('catalog_category_entity')], ['entity_id', 'path'] + )->joinInner( + ['ccei' => $this->getTable('catalog_category_entity_int')], + 'ccei.' . $categoryLinkField . ' = c.' . $categoryLinkField . + ' AND ccei.attribute_id = ' . $isActiveAttributeId . + ' AND ccei.value = 1', + ['store_id'] ), 'entity_id' ); @@ -674,13 +699,13 @@ protected function fillTempCategoryTreeIndex($temporaryName) foreach ($this->connection->fetchAll($select) as $category) { foreach (explode('/', $category['path']) as $parentId) { if ($parentId !== $category['entity_id']) { - $values[] = [$parentId, $category['entity_id']]; + $values[] = [$parentId, $category['entity_id'], $category['store_id']]; } } } if (count($values) > 0) { - $this->connection->insertArray($temporaryName, ['parent_id', 'child_id'], $values); + $this->connection->insertArray($temporaryName, ['parent_id', 'child_id', 'store_id'], $values); } } } From 5a38724d165ffd0c325d015cffaf7732834b7157 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Mon, 24 Sep 2018 20:00:27 +0300 Subject: [PATCH 0087/1158] MAGETWO-91650: Translation not working for product alerts - Add store id for product alert --- .../ProductAlert/Controller/Add/Price.php | 16 +++--- .../ProductAlert/Controller/Add/Stock.php | 28 ++++++++--- app/code/Magento/ProductAlert/Model/Email.php | 49 +++++++++++++------ .../Magento/ProductAlert/Model/Observer.php | 19 +++++++ app/code/Magento/ProductAlert/Model/Price.php | 10 ++++ app/code/Magento/ProductAlert/Model/Stock.php | 10 ++++ .../Magento/ProductAlert/etc/db_schema.xml | 16 ++++++ .../ProductAlert/etc/db_schema_whitelist.json | 20 +++++--- 8 files changed, 133 insertions(+), 35 deletions(-) diff --git a/app/code/Magento/ProductAlert/Controller/Add/Price.php b/app/code/Magento/ProductAlert/Controller/Add/Price.php index 04e623105e645..fbaff109fd15a 100644 --- a/app/code/Magento/ProductAlert/Controller/Add/Price.php +++ b/app/code/Magento/ProductAlert/Controller/Add/Price.php @@ -6,6 +6,7 @@ namespace Magento\ProductAlert\Controller\Add; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\ProductAlert\Controller\Add as AddController; use Magento\Framework\App\Action\Context; use Magento\Customer\Model\Session as CustomerSession; @@ -16,7 +17,10 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\NoSuchEntityException; -class Price extends AddController +/** + * Controller for notifying about price. + */ +class Price extends AddController implements HttpPostActionInterface { /** * @var \Magento\Store\Model\StoreManagerInterface @@ -62,6 +66,8 @@ protected function isInternal($url) } /** + * Method for adding info about product alert price. + * * @return \Magento\Framework\Controller\Result\Redirect */ public function execute() @@ -75,6 +81,7 @@ public function execute() return $resultRedirect; } + $store = $this->storeManager->getStore(); try { /* @var $product \Magento\Catalog\Model\Product */ $product = $this->productRepository->getById($productId); @@ -83,11 +90,8 @@ public function execute() ->setCustomerId($this->customerSession->getCustomerId()) ->setProductId($product->getId()) ->setPrice($product->getFinalPrice()) - ->setWebsiteId( - $this->_objectManager->get(\Magento\Store\Model\StoreManagerInterface::class) - ->getStore() - ->getWebsiteId() - ); + ->setWebsiteId($store->getWebsiteId()) + ->setStoreId($store->getId()); $model->save(); $this->messageManager->addSuccess(__('You saved the alert subscription.')); } catch (NoSuchEntityException $noEntityException) { diff --git a/app/code/Magento/ProductAlert/Controller/Add/Stock.php b/app/code/Magento/ProductAlert/Controller/Add/Stock.php index 56d052f7e11e2..24cab39d544fc 100644 --- a/app/code/Magento/ProductAlert/Controller/Add/Stock.php +++ b/app/code/Magento/ProductAlert/Controller/Add/Stock.php @@ -6,6 +6,7 @@ namespace Magento\ProductAlert\Controller\Add; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\ProductAlert\Controller\Add as AddController; use Magento\Framework\App\Action\Context; use Magento\Customer\Model\Session as CustomerSession; @@ -13,29 +14,44 @@ use Magento\Framework\App\Action\Action; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Model\StoreManagerInterface; -class Stock extends AddController +/** + * Controller for notifying about stock. + */ +class Stock extends AddController implements HttpPostActionInterface { /** * @var \Magento\Catalog\Api\ProductRepositoryInterface */ protected $productRepository; + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * @param \Magento\Framework\App\Action\Context $context * @param \Magento\Customer\Model\Session $customerSession * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository + * @param StoreManagerInterface|null $storeManager */ public function __construct( Context $context, CustomerSession $customerSession, - ProductRepositoryInterface $productRepository + ProductRepositoryInterface $productRepository, + StoreManagerInterface $storeManager = null ) { $this->productRepository = $productRepository; parent::__construct($context, $customerSession); + $this->storeManager = $storeManager ?: $this->_objectManager + ->get(\Magento\Store\Model\StoreManagerInterface::class); } /** + * Method for adding info about product alert stock. + * * @return \Magento\Framework\Controller\Result\Redirect */ public function execute() @@ -52,15 +68,13 @@ public function execute() try { /* @var $product \Magento\Catalog\Model\Product */ $product = $this->productRepository->getById($productId); + $store = $this->storeManager->getStore(); /** @var \Magento\ProductAlert\Model\Stock $model */ $model = $this->_objectManager->create(\Magento\ProductAlert\Model\Stock::class) ->setCustomerId($this->customerSession->getCustomerId()) ->setProductId($product->getId()) - ->setWebsiteId( - $this->_objectManager->get(\Magento\Store\Model\StoreManagerInterface::class) - ->getStore() - ->getWebsiteId() - ); + ->setWebsiteId($store->getWebsiteId()) + ->setStoreId($store->getId()); $model->save(); $this->messageManager->addSuccess(__('Alert subscription has been saved.')); } catch (NoSuchEntityException $noEntityException) { diff --git a/app/code/Magento/ProductAlert/Model/Email.php b/app/code/Magento/ProductAlert/Model/Email.php index 90d9e261f97d5..18adc54c2d660 100644 --- a/app/code/Magento/ProductAlert/Model/Email.php +++ b/app/code/Magento/ProductAlert/Model/Email.php @@ -136,6 +136,11 @@ class Email extends AbstractModel */ protected $_customerHelper; + /** + * @var int + */ + private $storeId = null; + /** * @param Context $context * @param Registry $registry @@ -210,6 +215,18 @@ public function setWebsite(\Magento\Store\Model\Website $website) return $this; } + /** + * Set store id from product alert. + * + * @param int $storeId + * @return $this + */ + public function setStoreId(int $storeId) + { + $this->storeId = $storeId; + return $this; + } + /** * Set website id * @@ -330,29 +347,18 @@ protected function _getStockBlock() */ public function send() { - if ($this->_website === null || $this->_customer === null) { - return false; - } - - if (!$this->_website->getDefaultGroup() || !$this->_website->getDefaultGroup()->getDefaultStore()) { - return false; - } - - if (!in_array($this->_type, ['price', 'stock'])) { + if ($this->_website === null || $this->_customer === null || !$this->isExistDefaultStore()) { return false; } $products = $this->getProducts(); - if (count($products) === 0) { - return false; - } - $templateConfigPath = $this->getTemplateConfigPath(); - if (!$templateConfigPath) { + if (!in_array($this->_type, ['price', 'stock']) || count($products) === 0 || !$templateConfigPath) { return false; } - $store = $this->_website->getDefaultStore(); + $storeId = $this->storeId ?: (int) $this->_customer->getStoreId(); + $store = $this->getStore($storeId); $storeId = $store->getId(); $this->_appEmulation->startEnvironmentEmulation($storeId); @@ -438,4 +444,17 @@ private function getTemplateConfigPath(): string ? self::XML_PATH_EMAIL_PRICE_TEMPLATE : self::XML_PATH_EMAIL_STOCK_TEMPLATE; } + + /** + * Check if exists default store. + * + * @return bool + */ + private function isExistDefaultStore(): bool + { + if (!$this->_website->getDefaultGroup() || !$this->_website->getDefaultGroup()->getDefaultStore()) { + return false; + } + return true; + } } diff --git a/app/code/Magento/ProductAlert/Model/Observer.php b/app/code/Magento/ProductAlert/Model/Observer.php index 1870989f11dc7..addc61d2f49a9 100644 --- a/app/code/Magento/ProductAlert/Model/Observer.php +++ b/app/code/Magento/ProductAlert/Model/Observer.php @@ -218,6 +218,7 @@ protected function _processPrice(\Magento\ProductAlert\Model\Email $email) $previousCustomer = null; $email->setWebsite($website); foreach ($collection as $alert) { + $this->setAlertStoreId($alert, $email); try { if (!$previousCustomer || $previousCustomer->getId() != $alert->getCustomerId()) { $customer = $this->customerRepository->getById($alert->getCustomerId()); @@ -311,6 +312,7 @@ protected function _processStock(\Magento\ProductAlert\Model\Email $email) $previousCustomer = null; $email->setWebsite($website); foreach ($collection as $alert) { + $this->setAlertStoreId($alert, $email); try { if (!$previousCustomer || $previousCustomer->getId() != $alert->getCustomerId()) { $customer = $this->customerRepository->getById($alert->getCustomerId()); @@ -427,4 +429,21 @@ public function process() return $this; } + + /** + * Set alert store id. + * + * @param \Magento\ProductAlert\Model\Price|\Magento\ProductAlert\Model\Stock $alert + * @param Email $email + * @return Observer + */ + private function setAlertStoreId($alert, \Magento\ProductAlert\Model\Email $email) : Observer + { + $alertStoreId = $alert->getStoreId(); + if ($alertStoreId) { + $email->setStoreId((int)$alertStoreId); + } + + return $this; + } } diff --git a/app/code/Magento/ProductAlert/Model/Price.php b/app/code/Magento/ProductAlert/Model/Price.php index 0c12b7cfb489e..ecdf4578838aa 100644 --- a/app/code/Magento/ProductAlert/Model/Price.php +++ b/app/code/Magento/ProductAlert/Model/Price.php @@ -26,6 +26,8 @@ * @method \Magento\ProductAlert\Model\Price setSendCount(int $value) * @method int getStatus() * @method \Magento\ProductAlert\Model\Price setStatus(int $value) + * @method int getStoreId() + * @method \Magento\ProductAlert\Model\Stock setStoreId(int $value) * * @author Magento Core Team <core@magentocommerce.com> * @@ -60,6 +62,8 @@ public function __construct( } /** + * Create customer collection. + * * @return void */ protected function _construct() @@ -68,6 +72,8 @@ protected function _construct() } /** + * Create customer collection. + * * @return Collection */ public function getCustomerCollection() @@ -76,6 +82,8 @@ public function getCustomerCollection() } /** + * Load by param. + * * @return $this */ public function loadByParam() @@ -87,6 +95,8 @@ public function loadByParam() } /** + * Method for deleting customer from website. + * * @param int $customerId * @param int $websiteId * @return $this diff --git a/app/code/Magento/ProductAlert/Model/Stock.php b/app/code/Magento/ProductAlert/Model/Stock.php index 4d4dea5c2fe7e..99ba95e633904 100644 --- a/app/code/Magento/ProductAlert/Model/Stock.php +++ b/app/code/Magento/ProductAlert/Model/Stock.php @@ -24,6 +24,8 @@ * @method \Magento\ProductAlert\Model\Stock setSendCount(int $value) * @method int getStatus() * @method \Magento\ProductAlert\Model\Stock setStatus(int $value) + * @method int getStoreId() + * @method \Magento\ProductAlert\Model\Stock setStoreId(int $value) * * @author Magento Core Team <core@magentocommerce.com> * @@ -58,6 +60,8 @@ public function __construct( } /** + * Class constructor. + * * @return void */ protected function _construct() @@ -66,6 +70,8 @@ protected function _construct() } /** + * Create customer collection. + * * @return Collection */ public function getCustomerCollection() @@ -74,6 +80,8 @@ public function getCustomerCollection() } /** + * Load by param. + * * @return $this */ public function loadByParam() @@ -85,6 +93,8 @@ public function loadByParam() } /** + * Method for deleting customer from website. + * * @param int $customerId * @param int $websiteId * @return $this diff --git a/app/code/Magento/ProductAlert/etc/db_schema.xml b/app/code/Magento/ProductAlert/etc/db_schema.xml index ddf8be8a37e9c..1d145482ea38f 100644 --- a/app/code/Magento/ProductAlert/etc/db_schema.xml +++ b/app/code/Magento/ProductAlert/etc/db_schema.xml @@ -18,6 +18,8 @@ comment="Price amount"/> <column xsi:type="smallint" name="website_id" padding="5" unsigned="true" nullable="false" identity="false" default="0" comment="Website id"/> + <column xsi:type="smallint" name="store_id" padding="5" unsigned="true" nullable="true" identity="false" + default="0" comment="Store id"/> <column xsi:type="timestamp" name="add_date" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="Product alert add date"/> <column xsi:type="timestamp" name="last_send_date" on_update="false" nullable="true" @@ -38,6 +40,9 @@ <constraint xsi:type="foreign" name="PRODUCT_ALERT_PRICE_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID" table="product_alert_price" column="website_id" referenceTable="store_website" referenceColumn="website_id" onDelete="CASCADE"/> + <constraint xsi:type="foreign" name="PRODUCT_ALERT_PRICE_STORE_ID_STORE_STORE_ID" + table="product_alert_stock" column="website_id" referenceTable="store" + referenceColumn="store_id" onDelete="CASCADE"/> <index name="PRODUCT_ALERT_PRICE_CUSTOMER_ID" indexType="btree"> <column name="customer_id"/> </index> @@ -47,6 +52,9 @@ <index name="PRODUCT_ALERT_PRICE_WEBSITE_ID" indexType="btree"> <column name="website_id"/> </index> + <index name="PRODUCT_ALERT_PRICE_STORE_ID" indexType="btree"> + <column name="store_id"/> + </index> </table> <table name="product_alert_stock" resource="default" engine="innodb" comment="Product Alert Stock"> <column xsi:type="int" name="alert_stock_id" padding="10" unsigned="true" nullable="false" identity="true" @@ -57,6 +65,8 @@ default="0" comment="Product id"/> <column xsi:type="smallint" name="website_id" padding="5" unsigned="true" nullable="false" identity="false" default="0" comment="Website id"/> + <column xsi:type="smallint" name="store_id" padding="5" unsigned="true" nullable="true" identity="false" + default="0" comment="Store id"/> <column xsi:type="timestamp" name="add_date" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="Product alert add date"/> <column xsi:type="timestamp" name="send_date" on_update="false" nullable="true" @@ -71,6 +81,9 @@ <constraint xsi:type="foreign" name="PRODUCT_ALERT_STOCK_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID" table="product_alert_stock" column="website_id" referenceTable="store_website" referenceColumn="website_id" onDelete="CASCADE"/> + <constraint xsi:type="foreign" name="PRODUCT_ALERT_STOCK_STORE_ID_STORE_STORE_ID" + table="product_alert_stock" column="website_id" referenceTable="store" + referenceColumn="store_id" onDelete="CASCADE"/> <constraint xsi:type="foreign" name="PRODUCT_ALERT_STOCK_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID" table="product_alert_stock" column="customer_id" referenceTable="customer_entity" referenceColumn="entity_id" onDelete="CASCADE"/> @@ -86,5 +99,8 @@ <index name="PRODUCT_ALERT_STOCK_WEBSITE_ID" indexType="btree"> <column name="website_id"/> </index> + <index name="PRODUCT_ALERT_STOCK_STORE_ID" indexType="btree"> + <column name="store_id"/> + </index> </table> </schema> diff --git a/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json b/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json index 266d00e04c5bc..234e3d14876e5 100644 --- a/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json +++ b/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json @@ -9,19 +9,22 @@ "add_date": true, "last_send_date": true, "send_count": true, - "status": true + "status": true, + "store_id": true }, "index": { "PRODUCT_ALERT_PRICE_CUSTOMER_ID": true, "PRODUCT_ALERT_PRICE_PRODUCT_ID": true, - "PRODUCT_ALERT_PRICE_WEBSITE_ID": true + "PRODUCT_ALERT_PRICE_WEBSITE_ID": true, + "PRODUCT_ALERT_PRICE_STORE_ID": true }, "constraint": { "PRIMARY": true, "PRODUCT_ALERT_PRICE_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID": true, "PRODUCT_ALERT_PRICE_PRODUCT_ID_CATALOG_PRODUCT_ENTITY_ENTITY_ID": true, "PRODUCT_ALERT_PRICE_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID": true, - "PRODUCT_ALERT_PRICE_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true + "PRODUCT_ALERT_PRICE_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true, + "PRODUCT_ALERT_PRICE_STORE_ID_STORE_STORE_ID": true } }, "product_alert_stock": { @@ -33,19 +36,22 @@ "add_date": true, "send_date": true, "send_count": true, - "status": true + "status": true, + "store_id": true }, "index": { "PRODUCT_ALERT_STOCK_CUSTOMER_ID": true, "PRODUCT_ALERT_STOCK_PRODUCT_ID": true, - "PRODUCT_ALERT_STOCK_WEBSITE_ID": true + "PRODUCT_ALERT_STOCK_WEBSITE_ID": true, + "PRODUCT_ALERT_STOCK_STORE_ID": true }, "constraint": { "PRIMARY": true, "PRODUCT_ALERT_STOCK_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID": true, "PRODUCT_ALERT_STOCK_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID": true, "PRODUCT_ALERT_STOCK_PRODUCT_ID_CATALOG_PRODUCT_ENTITY_ENTITY_ID": true, - "PRODUCT_ALERT_STOCK_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true + "PRODUCT_ALERT_STOCK_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true, + "PRODUCT_ALERT_STOCK_STORE_ID_STORE_STORE_ID": true } } -} \ No newline at end of file +} From 2034958405344006414e44804b914dd4cbdb9e46 Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Tue, 25 Sep 2018 12:58:19 +0400 Subject: [PATCH 0088/1158] MAGETWO-91628: Bundle product price doubled when switching currency - Add automation test --- ...tAddProductToCartFromBundleActionGroup.xml | 24 ++++++ .../Mftf/Section/StorefrontBundledSection.xml | 5 +- ...urrencyChangingBundleProductInCartTest.xml | 77 +++++++++++++++++++ .../Mftf/Page/ConfigCurrencySetupPage.xml | 13 ++++ .../Mftf/Section/CurrencySetupSection.xml | 14 ++++ 5 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml create mode 100644 app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml create mode 100644 app/code/Magento/CurrencySymbol/Test/Mftf/Page/ConfigCurrencySetupPage.xml create mode 100644 app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml new file mode 100644 index 0000000000000..441303e8f1b84 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StoreFrontAddProductToCartFromBundleWithCurrencyActionGroup"> + <arguments> + <argument name="product"/> + <argument name="currency" type="string" defaultValue="US Dollar"/> + </arguments> + <click selector="{{StorefrontBundledSection.currencyTrigger}}" stepKey="openCurrencyTrigger"/> + <click selector="{{StorefrontBundledSection.currency(currency)}}" stepKey="chooseCurrency"/> + <click selector="{{StorefrontBundledSection.addToCart}}" stepKey="clickCustomize"/> + <waitForPageLoad stepKey="waitForBundleOpen"/> + <checkOption selector="{{StorefrontBundledSection.productInBundle(product.name)}}" stepKey="chooseProduct"/> + <click selector="{{StorefrontBundledSection.addToCartConfigured}}" stepKey="addToCartProduct"/> + <scrollToTopOfPage stepKey="scrollToTop"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml index f724f9bbfe1bd..5646ecf812a3f 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="StorefrontBundledSection"> <element name="nthBundledOption" type="input" selector=".option:nth-of-type({{numOption}}) .choice:nth-of-type({{numOptionSelect}}) input" parameterized="true"/> <element name="addToCart" type="button" selector="#bundle-slide" timeout="30"/> @@ -24,10 +24,13 @@ <element name="bundleProductName" type="text" selector="//*[@id='maincontent']//span[@itemprop='name']"/> <element name="pageNotFound" type="text" selector="//h1[@class='page-title']//span[contains(., 'Whoops, our bad...')]"/> <element name="dropDownOptionOneProducts" type="select" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//select" parameterized="true"/> + <element name="productInBundle" type="select" selector="//label//span[contains(text(), '{{productName}}')]" parameterized="true"/> <element name="dropDownOptionOneQuantity" type="input" selector="//span[contains(text(), '{{productName}}')]/../..//input" parameterized="true"/> <element name="radioButtonOptionTwoProducts" type="checkbox" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//div[@class='field choice'][{{productNumber}}]/input" parameterized="true"/> <element name="radioButtonOptionTwoQuantity" type="input" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//div[@class='field qty qty-holder']//input" parameterized="true"/> <element name="checkboxOptionThreeProducts" type="checkbox" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//div[@class='field choice'][{{productNumber}}]/input" parameterized="true"/> <element name="multiselectOptionFourProducts" type="multiselect" selector="//label//span[contains(text(), '{{productName}}')]/../..//select[@multiple='multiple']" parameterized="true"/> + <element name="currencyTrigger" type="select" selector="#switcher-currency-trigger" timeout="30"/> + <element name="currency" type="select" selector="//a[text()='{{arg}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml new file mode 100644 index 0000000000000..b7e716dc15ece --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CurrencyChangingBundleProductInCartTest"> + <annotations> + <features value="Bundle"/> + <stories value="Check that after changing currency price of cart is correct when the bundle product added to the cart"/> + <title value="User should be able change the currency and get right price in cart when the bundle product added to the cart"/> + <description value="User should be able change the currency and add one more product in cart and get right price in previous currency"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-94467"/> + <group value="Bundle"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"/> + </before> + <after> + <!-- Delete the bundled product --> + <actionGroup stepKey="deleteBundle" ref="deleteProductUsingProductGrid"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="ClearFiltersAfter"/> + <!--Clear Configs--> + <amOnPage url="{{AdminLoginPage.url}}" stepKey="navigateToAdmin"/> + <waitForPageLoad stepKey="waitForAdminLoginPageLoad"/> + <amOnPage url="{{ConfigCurrencySetupPage.url}}" stepKey="navigateToConfigCurrencySetupPage"/> + <waitForPageLoad stepKey="waitForConfigCurrencySetupPageForUnselectEuroCurrency"/> + <unselectOption selector="{{CurrencySetupSection.allowCurrencies}}" userInput="Euro" stepKey="unselectEuro"/> + <click stepKey="saveUnselectedConfigs" selector="{{AdminConfigSection.saveButton}}"/> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="logout"/> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + </after> + <!--Go to bundle product creation page--> + <amOnPage url="{{AdminProductCreatePage.url(BundleProduct.set, BundleProduct.type)}}" stepKey="goToBundleProductCreationPage"/> + <waitForPageLoad stepKey="waitForBundleProductCreatePageToLoad"/> + <actionGroup ref="fillMainBundleProductForm" stepKey="fillMainFieldsForBundle"/> + <!-- Add Option, a "Radio Buttons" type option --> + <actionGroup ref="addBundleOptionWithTwoProducts" stepKey="addBundleOptionWithTwoProducts2"> + <argument name="x" value="0"/> + <argument name="n" value="1"/> + <argument name="prodOneSku" value="$$simpleProduct1.sku$$"/> + <argument name="prodTwoSku" value="$$simpleProduct2.sku$$"/> + <argument name="optionTitle" value="Option"/> + <argument name="inputType" value="radio"/> + </actionGroup> + <checkOption selector="{{AdminProductFormBundleSection.userDefinedQuantity('0', '0')}}" stepKey="userDefinedQuantitiyOptionProduct0"/> + <checkOption selector="{{AdminProductFormBundleSection.userDefinedQuantity('0', '1')}}" stepKey="userDefinedQuantitiyOptionProduct1"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + <amOnPage url="{{ConfigCurrencySetupPage.url}}" stepKey="navigateToConfigCurrencySetupPage"/> + <waitForPageLoad stepKey="waitForConfigCurrencySetupPage"/> + <selectOption selector="{{CurrencySetupSection.allowCurrencies}}" parameterArray="['Euro', 'US Dollar']" stepKey="selectCurrencies"/> + <click stepKey="saveConfigs" selector="{{AdminConfigSection.saveButton}}"/> + <!-- Go to storefront BundleProduct --> + <amOnPage url="{{BundleProduct.sku}}.html" stepKey="goToStorefront"/> + <waitForPageLoad stepKey="waitForStorefront"/> + <actionGroup ref="StoreFrontAddProductToCartFromBundleWithCurrencyActionGroup" stepKey="addProduct1ToCartAndChangeCurrencyToEuro"> + <argument name="product" value="$$simpleProduct1$$"/> + <argument name="currency" value="EUR - Euro"/> + </actionGroup> + <actionGroup ref="StoreFrontAddProductToCartFromBundleWithCurrencyActionGroup" stepKey="addProduct2ToCartAndChangeCurrencyToUSD"> + <argument name="product" value="$$simpleProduct2$$"/> + <argument name="currency" value="USD - US Dollar"/> + </actionGroup> + <click stepKey="openMiniCart" selector="{{StorefrontMinicartSection.showCart}}"/> + <waitForPageLoad stepKey="waitForMiniCart"/> + <see stepKey="seeCartSubtotal" userInput="$12,300.00"/> + </test> +</tests> diff --git a/app/code/Magento/CurrencySymbol/Test/Mftf/Page/ConfigCurrencySetupPage.xml b/app/code/Magento/CurrencySymbol/Test/Mftf/Page/ConfigCurrencySetupPage.xml new file mode 100644 index 0000000000000..f523cb58d3bb6 --- /dev/null +++ b/app/code/Magento/CurrencySymbol/Test/Mftf/Page/ConfigCurrencySetupPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="ConfigCurrencySetupPage" url="admin/system_config/edit/section/currency" area="admin" module="Magento_Config"> + </page> +</pages> diff --git a/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml b/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml new file mode 100644 index 0000000000000..16101409ad7e8 --- /dev/null +++ b/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="CurrencySetupSection"> + <element name="allowCurrencies" type="select" selector="#currency_options_allow"/> + </section> +</sections> \ No newline at end of file From 25cedef8c15ead70195ec7117f4995fbcd5bddf2 Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Tue, 25 Sep 2018 13:03:19 +0400 Subject: [PATCH 0089/1158] MAGETWO-91628: Bundle product price doubled when switching currency - Revert xsi --- .../Bundle/Test/Mftf/Section/StorefrontBundledSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml index 5646ecf812a3f..ad74cfff54bd9 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontBundledSection"> <element name="nthBundledOption" type="input" selector=".option:nth-of-type({{numOption}}) .choice:nth-of-type({{numOptionSelect}}) input" parameterized="true"/> <element name="addToCart" type="button" selector="#bundle-slide" timeout="30"/> From cdd19a602f03b0da45bf36e6ea634ec2bae5be29 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Tue, 25 Sep 2018 12:55:32 +0300 Subject: [PATCH 0090/1158] Update Comments --- app/code/Magento/Sales/Model/Order/Address.php | 6 +----- app/code/Magento/Sales/Model/Order/Payment/Transaction.php | 6 +----- app/code/Magento/Store/Model/Store.php | 5 +---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index 8a4406e17a7e6..98433899cca26 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -508,11 +508,7 @@ public function getVatRequestSuccess() } /** - * Set Parent ID - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setParentId($id) { diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index d1a8e99a98027..8f9f275de1658 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -833,11 +833,7 @@ public function getTransactionId() } /** - * Set Transaction ID - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setTransactionId($id) { diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 31d2b7bf30327..c212ebfec845f 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1378,10 +1378,7 @@ public function getStorePath() } /** - * Get scope type - * - * @return string - * @since 100.1.0 + * @inheritdoc */ public function getScopeType() { From d447ad902a61a3ef6b4b1f2303edfee479d1112e Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Tue, 25 Sep 2018 15:29:09 +0400 Subject: [PATCH 0091/1158] MAGETWO-91609: Problems with operator more/less in the "catalog Products List" widget - Add automated test --- .../Section/AdminCategoryContentSection.xml | 1 + .../AdminCategoryDisplaySettingsSection.xml | 15 ++ .../AdminCreateBlockWithWidgetActionGroup.xml | 49 ++++++ .../Mftf/Section/CatalogWidgetSection.xml | 25 +++ .../CatalogProductListWidgetOperatorsTest.xml | 156 ++++++++++++++++++ 5 files changed, 246 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml create mode 100644 app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml create mode 100644 app/code/Magento/CatalogWidget/Test/Mftf/Section/CatalogWidgetSection.xml create mode 100644 app/code/Magento/CatalogWidget/Test/Mftf/Test/CatalogProductListWidgetOperatorsTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml index 59537274f23c9..742ff4760eada 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml @@ -15,5 +15,6 @@ <element name="uploadImageFile" type="input" selector=".file-uploader-area>input"/> <element name="imageFileName" type="text" selector=".file-uploader-filename"/> <element name="removeImageButton" type="button" selector=".file-uploader-summary .action-remove"/> + <element name="AddCMSBlock" type="select" selector="//*[@name='landing_page']"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml new file mode 100644 index 0000000000000..daa00eb0a27b7 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCategoryDisplaySettingsSection"> + <element name="settingsHeader" type="button" selector="//*[contains(text(),'Display Settings')]" timeout="30"/> + <element name="displayMode" type="button" selector="//*[@name='display_mode']"/> + </section> +</sections> diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml b/app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml new file mode 100644 index 0000000000000..1f54ff40283b1 --- /dev/null +++ b/app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateBlockWithWidget"> + <arguments> + <argument name="addCondition" type="string"/> + <argument name="isCondition" type="string"/> + <argument name="fieldCondition" type="string"/> + </arguments> + + <click stepKey="clickShowHideButton" selector="{{BlockWYSIWYGSection.ShowHideBtn}}"/> + <waitForElementVisible stepKey="waitForInsertWidgetButton" selector="{{CatalogWidgetSection.insertWidgetButton}}"/> + + <selectOption stepKey="selectAllStoreView" userInput="All Store Views" selector="{{CatalogWidgetSection.storeViewOption}}"/> + <fillField selector="{{BlockContentSection.TextArea}}" userInput="" stepKey="makeContentFieldEmpty"/> + + <click selector="{{CatalogWidgetSection.insertWidgetButton}}" stepKey="clickInsertWidgetButton"/> + <waitForElementVisible stepKey="waitForInsertWidgetFrame" selector="{{InsertWidgetSection.widgetTypeDropDown}}" time="10"/> + + <selectOption selector="{{InsertWidgetSection.widgetTypeDropDown}}" userInput="Catalog Products List" stepKey="selectCatalogProductListOption"/> + <waitForElementVisible stepKey="waitForConditionsElementBecomeAvailable" selector="{{InsertWidgetSection.conditionsAddButton}}"/> + + <click selector="{{InsertWidgetSection.conditionsAddButton}}" stepKey="clickToAddCondition"/> + <waitForElementVisible stepKey="waitForSelectBoxOpened" selector="{{InsertWidgetSection.conditionsSelectBox}}"/> + + <selectOption selector="{{InsertWidgetSection.conditionsSelectBox}}" userInput="{{addCondition}}" stepKey="selectConditionsSelectBox"/> + <waitForElementVisible stepKey="seeConditionsAdded" selector="{{InsertWidgetSection.addCondition('1')}}"/> + + <click selector="{{InsertWidgetSection.conditionIs}}" stepKey="clickToConditionIs"/> + <selectOption selector="{{InsertWidgetSection.conditionOperator('1')}}" stepKey="selectOperatorGreaterThan" userInput="{{isCondition}}"/> + + <click selector="{{InsertWidgetSection.addCondition('1')}}" stepKey="clickAddConditionItem"/> + <waitForElementVisible stepKey="waitForConditionFieldOpened" selector="{{InsertWidgetSection.conditionField('1')}}"/> + + <fillField selector="{{InsertWidgetSection.conditionField('1')}}" stepKey="setOperator" userInput="{{fieldCondition}}"/> + <click selector="{{WidgetSection.InsertWidget}}" stepKey="clickInsertWidget"/> + + <waitForElementVisible stepKey="waitForInsertWidgetSaved" selector="{{InsertWidgetSection.save}}"/> + <click stepKey="clickSaveButton" selector="{{InsertWidgetSection.save}}"/> + <see userInput="You saved the block." stepKey="seeSavedBlockMsgOnForm"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Section/CatalogWidgetSection.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Section/CatalogWidgetSection.xml new file mode 100644 index 0000000000000..2957cfdfe6f43 --- /dev/null +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Section/CatalogWidgetSection.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="CatalogWidgetSection"> + <element name="insertWidgetButton" type="button" selector=".scalable.action-add-widget.plugin"/> + <element name="storeViewOption" type="button" selector="//*[@name='store_id']"/> + </section> + + <section name="InsertWidgetSection"> + <element name="widgetTypeDropDown" type="select" selector="#select_widget_type"/> + <element name="conditionsAddButton" type="button" selector=".rule-param.rule-param-new-child"/> + <element name="conditionsSelectBox" type="button" selector="#conditions__1__new_child"/> + <element name="addCondition" type="button" selector="//*[@id='conditions__1--{{arg1}}__value']/../preceding-sibling::a" parameterized="true"/> + <element name="conditionField" type="button" selector="#conditions__1--{{arg2}}__value" parameterized="true"/> + <element name="save" type="button" selector="#save-button"/> + <element name="conditionIs" type="button" selector="//*[@id='conditions__1--1__attribute']/following-sibling::span[1]"/> + <element name="conditionOperator" type="button" selector="#conditions__1--{{arg3}}__operator" parameterized="true"/> + <element name="checkElementStorefrontByPrice" type="button" selector="//*[@class='product-items widget-product-grid']//*[contains(text(),'${{arg4}}.00')]" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Test/CatalogProductListWidgetOperatorsTest.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Test/CatalogProductListWidgetOperatorsTest.xml new file mode 100644 index 0000000000000..53a4ccb608a6d --- /dev/null +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Test/CatalogProductListWidgetOperatorsTest.xml @@ -0,0 +1,156 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CatalogProductListWidgetOperatorsTest"> + <annotations> + <features value="CatalogWidget"/> + <stories value="MAGETWO-91609: Problems with operator more/less in the 'catalog Products List' widget"/> + <title value="Checking operator more/less in the 'catalog Products List' widget"/> + <description value="Check 'less than', 'equals or greater than', 'equals or less than' operators"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-94479"/> + <group value="CatalogWidget"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="simplecategory"/> + <createData entity="SimpleProduct" stepKey="createFirstProduct"> + <requiredEntity createDataKey="simplecategory"/> + <field key="price">10</field> + </createData> + <createData entity="SimpleProduct" stepKey="createSecondProduct"> + <requiredEntity createDataKey="simplecategory"/> + <field key="price">50</field> + </createData> + <createData entity="SimpleProduct" stepKey="createThirdProduct"> + <requiredEntity createDataKey="simplecategory"/> + <field key="price">100</field> + </createData> + + <createData entity="_defaultBlock" stepKey="createPreReqBlock"/> + <!--User log in on back-end as admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="EnabledWYSIWYG" stepKey="enableWYSIWYG"/> + </before> + + <!--Open block with widget.--> + <actionGroup ref="navigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage1"> + <argument name="CMSBlockPage" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateBlockWithWidget" stepKey="adminCreateBlockWithWidget"> + <argument name="addCondition" value="Price"/> + <argument name="isCondition" value="greater than"/> + <argument name="fieldCondition" value="20"/> + </actionGroup> + + <!--Go to Catalog > Categories (choose category where created products)--> + <amOnPage url="{{AdminCategoryPage.url}}" stepKey="onCategoryIndexPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoadAddProducts" after="onCategoryIndexPage"/> + <click selector="{{AdminCategorySidebarTreeSection.expandAll}}" stepKey="clickExpandAll" after="waitForCategoryPageLoadAddProducts"/> + <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(SimpleSubCategory.name)}}" stepKey="clickCategoryLink"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + + <!--Content > Add CMS Block: name saved block--> + <waitForElementVisible selector="{{AdminCategoryContentSection.sectionHeader}}" stepKey="waitForContentSection"/> + <conditionalClick selector="{{AdminCategoryContentSection.sectionHeader}}" dependentSelector="{{AdminCategoryContentSection.uploadButton}}" visible="false" stepKey="openContentSection"/> + <waitForPageLoad stepKey="waitForContentLoad"/> + + <selectOption selector="{{AdminCategoryContentSection.AddCMSBlock}}" stepKey="selectSavedBlock" userInput="{{_defaultBlock.title}}"/> + + <!--Display Settings > Display Mode: Static block only--> + <waitForElementVisible selector="{{AdminCategoryDisplaySettingsSection.settingsHeader}}" stepKey="waitForDisplaySettingsSection"/> + <conditionalClick selector="{{AdminCategoryDisplaySettingsSection.settingsHeader}}" dependentSelector="{{AdminCategoryDisplaySettingsSection.displayMode}}" visible="false" stepKey="openDisplaySettingsSection"/> + <waitForPageLoad stepKey="waitForDisplaySettingsLoad"/> + <selectOption stepKey="selectStaticBlockOnlyOption" userInput="Static block only" selector="{{AdminCategoryDisplaySettingsSection.displayMode}}"/> + <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategoryWithProducts"/> + <waitForPageLoad stepKey="waitForCategorySaved"/> + <see userInput="You saved the category." stepKey="seeSuccessMessage"/> + + <!--Go to Storefront > category--> + <amOnPage url="$$simplecategory.name$$.html" stepKey="goToStorefrontCategoryPage"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoaded"/> + + <!--Check operators Greater than--> + <dontSeeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('10')}}" stepKey="dontSeeElementByPrice20"/> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('50')}}" stepKey="seeElementByPrice50"/> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('100')}}" stepKey="seeElementByPrice100"/> + + <!--Open block with widget.--> + <actionGroup ref="navigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage2"> + <argument name="CMSBlockPage" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateBlockWithWidget" stepKey="adminCreateBlockWithWidgetLessThan"> + <argument name="addCondition" value="Price"/> + <argument name="isCondition" value="less than"/> + <argument name="fieldCondition" value="20"/> + </actionGroup> + + <!--Go to Storefront > category--> + <amOnPage url="$$simplecategory.name$$.html" stepKey="goToStorefrontCategoryPage2"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoaded2"/> + + <!--Check operators Greater than--> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('10')}}" stepKey="seeElementByPrice20"/> + <dontSeeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('50')}}" stepKey="dontSeeElementByPrice50"/> + <dontSeeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('100')}}" stepKey="dontSeeElementByPrice100"/> + + <!--Open block with widget.--> + <actionGroup ref="navigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage3"> + <argument name="CMSBlockPage" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateBlockWithWidget" stepKey="adminCreateBlockWithWidgetEqualsOrGreaterThan"> + <argument name="addCondition" value="Price"/> + <argument name="isCondition" value="equals or greater than"/> + <argument name="fieldCondition" value="50"/> + </actionGroup> + + <!--Go to Storefront > category--> + <amOnPage url="$$simplecategory.name$$.html" stepKey="goToStorefrontCategoryPage3"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoaded3"/> + + <!--Check operators Greater than--> + <dontSeeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('10')}}" stepKey="dontSeeElementByPrice20s"/> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('50')}}" stepKey="seeElementByPrice50s"/> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('100')}}" stepKey="seeElementByPrice100s"/> + + <!--Open block with widget.--> + <actionGroup ref="navigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage4"> + <argument name="CMSBlockPage" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateBlockWithWidget" stepKey="adminCreateBlockWithWidgetEqualsOrLessThan"> + <argument name="addCondition" value="Price"/> + <argument name="isCondition" value="equals or less than"/> + <argument name="fieldCondition" value="50"/> + </actionGroup> + + <!--Go to Storefront > category--> + <amOnPage url="$$simplecategory.name$$.html" stepKey="goToStorefrontCategoryPage4"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoaded4"/> + + <!--Check operators Greater than--> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('10')}}" stepKey="seeElementByPrice20s"/> + <seeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('50')}}" stepKey="seeElementByPrice50t"/> + <dontSeeElement selector="{{InsertWidgetSection.checkElementStorefrontByPrice('100')}}" stepKey="dontSeeElementByPrice100s"/> + + <after> + <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> + <deleteData createDataKey="createPreReqBlock" stepKey="deletePreReqBlock" /> + <deleteData createDataKey="simplecategory" stepKey="deleteSimpleCategory"/> + <deleteData createDataKey="createFirstProduct" stepKey="deleteFirstProduct"/> + <deleteData createDataKey="createSecondProduct" stepKey="deleteSecondProduct"/> + <deleteData createDataKey="createThirdProduct" stepKey="deleteThirdProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + </test> +</tests> From 99b518a6ce248fc61db7a194a05d477422d71b2e Mon Sep 17 00:00:00 2001 From: Aleksey Tsoy <aleksey_tsoy@epam.com> Date: Tue, 25 Sep 2018 18:10:16 +0600 Subject: [PATCH 0092/1158] MAGETWO-91658: Wrong Checkout Totals Sort Order in cart - Added automated test --- .../Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml index e1ec9032e072a..08623da68a8ef 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml @@ -5,8 +5,7 @@ * See COPYING.txt for license details. */ --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="CheckoutTotalsSortOrderInCartTest"> <annotations> <title value="Checkout Totals Sort Order configuration and displaying in cart"/> From 1b8cd089461f20131a8b5e5784238918138e13ae Mon Sep 17 00:00:00 2001 From: Mikalai Shostka <mikalai_shostka@epam.com> Date: Tue, 25 Sep 2018 15:25:55 +0300 Subject: [PATCH 0093/1158] MAGETWO-70303: [GITHUB] Anchor categories are showing products of disabled subcategories #9002 - Change index table and temporary table --- .../Category/Product/AbstractAction.php | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index d312b78e74059..a1358c02ce9fc 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -123,6 +123,11 @@ abstract class AbstractAction */ private $queryGenerator; + /** + * @var int + */ + private $currentStoreId = 0; + /** * @param ResourceConnection $resource * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -164,6 +169,7 @@ protected function reindex() { foreach ($this->storeManager->getStores() as $store) { if ($this->getPathFromCategoryId($store->getRootCategoryId())) { + $this->currentStoreId = $store->getId(); $this->reindexRootCategory($store); $this->reindexAnchorCategories($store); $this->reindexNonAnchorCategories($store); @@ -499,7 +505,7 @@ protected function createAnchorSelect(Store $store) 'cc2.parent_id = cc.entity_id AND cc.entity_id NOT IN (' . implode( ',', $rootCatIds - ) . ') AND cc2.store_id = ' . $store->getId(), + ) . ')', [] )->joinInner( ['ccp' => $this->getTable('catalog_category_product')], @@ -631,12 +637,6 @@ protected function makeTempCategoryTreeIndex() null, ['nullable' => false, 'unsigned' => true] ); - $temporaryTable->addColumn( - 'store_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['nullable' => false, 'unsigned' => true] - ); // Each entry will be unique. $temporaryTable->addIndex( 'idx_primary', @@ -649,12 +649,6 @@ protected function makeTempCategoryTreeIndex() ['child_id'], ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] ); - - $temporaryTable->addIndex( - 'store_id', - ['store_id'], - ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] - ); // Drop the temporary table in case it already exists on this (persistent?) connection. $this->connection->dropTemporaryTable($temporaryName); $this->connection->createTemporaryTable($temporaryTable); @@ -684,11 +678,19 @@ protected function fillTempCategoryTreeIndex($temporaryName) ['c' => $this->getTable('catalog_category_entity')], ['entity_id', 'path'] )->joinInner( - ['ccei' => $this->getTable('catalog_category_entity_int')], - 'ccei.' . $categoryLinkField . ' = c.' . $categoryLinkField . - ' AND ccei.attribute_id = ' . $isActiveAttributeId . - ' AND ccei.value = 1', - ['store_id'] + ['ccacd' => $this->getTable('catalog_category_entity_int')], + 'ccacd.' . $categoryLinkField . ' = c.' . $categoryLinkField . ' AND ccacd.store_id = 0' . + ' AND ccacd.attribute_id = ' . $isActiveAttributeId, + [] + )->joinLeft( + ['ccacs' => $this->getTable('catalog_category_entity_int')], + 'ccacs.' . $categoryLinkField . ' = c.' . $categoryLinkField + . ' AND ccacs.attribute_id = ccacd.attribute_id AND ccacs.store_id = ' . + $this->currentStoreId, + [] + )->where( + $this->connection->getIfNullSql('ccacs.value', 'ccacd.value') . ' = ?', + 1 ), 'entity_id' ); @@ -699,13 +701,13 @@ protected function fillTempCategoryTreeIndex($temporaryName) foreach ($this->connection->fetchAll($select) as $category) { foreach (explode('/', $category['path']) as $parentId) { if ($parentId !== $category['entity_id']) { - $values[] = [$parentId, $category['entity_id'], $category['store_id']]; + $values[] = [$parentId, $category['entity_id']]; } } } if (count($values) > 0) { - $this->connection->insertArray($temporaryName, ['parent_id', 'child_id', 'store_id'], $values); + $this->connection->insertArray($temporaryName, ['parent_id', 'child_id'], $values); } } } From b2ef6286c38f7de0fd4646e5de9226f7ca03e8de Mon Sep 17 00:00:00 2001 From: Stsiapan Korf <Stsiapan_Korf@epam.com> Date: Tue, 25 Sep 2018 15:37:55 +0300 Subject: [PATCH 0094/1158] MAGETWO-91639: Tax is added despite customer group changes - Fix utf symbol --- app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php index af6599879de50..303c95b965b98 100644 --- a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php +++ b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php @@ -1,6 +1,6 @@ <?php /** - * Copyright Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); From 12634b0bc936f92ab8b37dbfec5f781e790551d7 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <horytsky@adobe.com> Date: Tue, 25 Sep 2018 15:57:04 +0300 Subject: [PATCH 0095/1158] MAGETWO-95137: [2.3] Return path e-mail variable system/smtp/return_path_email doesn't work --- app/code/Magento/Email/Model/Transport.php | 44 ++++++++++++++-------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Email/Model/Transport.php b/app/code/Magento/Email/Model/Transport.php index 5a4d64e6d6c0e..c270c3086cca9 100644 --- a/app/code/Magento/Email/Model/Transport.php +++ b/app/code/Magento/Email/Model/Transport.php @@ -31,6 +31,23 @@ class Transport implements TransportInterface */ const XML_PATH_SENDING_RETURN_PATH_EMAIL = 'system/smtp/return_path_email'; + /** + * Configuration of whether return path should be set or no. + * + * Possible values are: + * 0 - no + * 1 - yes (set value as FROM address) + * 2 - use custom value + * + * @var int + */ + private $isSetReturnPath; + + /** + * @var string|null + */ + private $returnPathValue; + /** * @var Sendmail */ @@ -51,25 +68,15 @@ public function __construct( ScopeConfigInterface $scopeConfig, $parameters = null ) { - /* configuration of whether return path should be set or no. Possible values are: - * 0 - no - * 1 - yes (set value as FROM address) - * 2 - use custom value - * @see Magento\Config\Model\Config\Source\Yesnocustom - */ - $isSetReturnPath = $scopeConfig->getValue( + $this->isSetReturnPath = (int) $scopeConfig->getValue( self::XML_PATH_SENDING_SET_RETURN_PATH, ScopeInterface::SCOPE_STORE ); - $returnPathValue = $scopeConfig->getValue( + $this->returnPathValue = $scopeConfig->getValue( self::XML_PATH_SENDING_RETURN_PATH_EMAIL, ScopeInterface::SCOPE_STORE ); - if ($isSetReturnPath == '2' && $returnPathValue !== null) { - $parameters .= ' -f' . \escapeshellarg($returnPathValue); - } - $this->zendTransport = new Sendmail($parameters); $this->message = $message; } @@ -80,9 +87,16 @@ public function __construct( public function sendMessage() { try { - $this->zendTransport->send( - Message::fromString($this->message->getRawMessage()) - ); + $zendMessage = Message::fromString($this->message->getRawMessage()); + if (2 === $this->isSetReturnPath && $this->returnPathValue) { + $zendMessage->setSender($this->returnPathValue); + } elseif (1 === $this->isSetReturnPath && $zendMessage->getFrom()->count()) { + $fromAddressList = $zendMessage->getFrom(); + $fromAddressList->rewind(); + $zendMessage->setSender($fromAddressList->current()->getEmail()); + } + + $this->zendTransport->send($zendMessage); } catch (\Exception $e) { throw new MailException(new Phrase($e->getMessage()), $e); } From ca3f8ba315ec2c810ee077ba1bacf7bcf371026a Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Tue, 25 Sep 2018 17:07:29 +0300 Subject: [PATCH 0096/1158] MAGETWO-91628: Bundle product price doubled when switching currency - Fixed unit tests; --- .../Bundle/Test/Unit/Model/Product/TypeTest.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php index 4bbf5641c55d3..9819abf62a273 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php @@ -513,10 +513,6 @@ function ($key) use ($optionCollection, $selectionCollection) { ->method('getSelectionId') ->willReturn(314); - $this->priceCurrency->expects($this->once()) - ->method('convert') - ->willReturn(3.14); - $result = $this->model->prepareForCartAdvanced($buyRequest, $product); $this->assertEquals([$product, $productType], $result); } @@ -737,10 +733,6 @@ function ($key) use ($optionCollection, $selectionCollection) { ->method('prepareForCart') ->willReturn([]); - $this->priceCurrency->expects($this->once()) - ->method('convert') - ->willReturn(3.14); - $result = $this->model->prepareForCartAdvanced($buyRequest, $product); $this->assertEquals('We can\'t add this item to your shopping cart right now.', $result); } @@ -961,10 +953,6 @@ function ($key) use ($optionCollection, $selectionCollection) { ->method('prepareForCart') ->willReturn('string'); - $this->priceCurrency->expects($this->once()) - ->method('convert') - ->willReturn(3.14); - $result = $this->model->prepareForCartAdvanced($buyRequest, $product); $this->assertEquals('string', $result); } From b7264dfc698df3536f82c5403fea685169b71226 Mon Sep 17 00:00:00 2001 From: Mikalai Shostka <mikalai_shostka@epam.com> Date: Tue, 25 Sep 2018 18:18:27 +0300 Subject: [PATCH 0097/1158] MAGETWO-91596: Making order in admin with grouped product by adding it by sku with empty qty field leads to unability to order - Add automated test --- .../AdminOrderFormItemsOrderedSection.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml new file mode 100644 index 0000000000000..11673f1f0fe26 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormItemsOrderedSection"> + <element name="addProductsBySku" type="button" selector="//section[@id='order-items']//span[contains(text(),'Add Products By SKU')]"/> + <element name="configureButtonBySku" type="button" selector="//div[@class='sku-configure-button']//span[contains(text(),'Configure')]"/> + <element name="configureProductOk" type="button" selector="//div[@class='page-main-actions']//span[contains(text(),'OK')]"/> + <element name="configureProductQtyField" type="input" selector="//*[@id='super-product-table']/tbody/tr[{{arg}}]/td[5]/input[1]" parameterized="true"/> + <element name="addProductToOrder" type="input" selector="//*[@title='Add Products to Order']"/> + <element name="itemsOrderedSummaryText" type="textarea" selector="//table[@class='data-table admin__table-primary order-tables']/tfoot/tr"/> + </section> +</sections> \ No newline at end of file From 23666acfbe35a00fe5c5be2c1e0e95440f32310f Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Tue, 25 Sep 2018 22:00:22 +0300 Subject: [PATCH 0098/1158] Add Catalog search action handle if no results --- .../Controller/Advanced/Result.php | 25 +++++++++- .../CatalogSearch/Controller/Result/Index.php | 23 ++++++--- .../Unit/Controller/Advanced/ResultTest.php | 49 ++++++++++++++++++- 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php index 2862efe4b4cd3..78890643c59fb 100644 --- a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php +++ b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php @@ -11,11 +11,15 @@ use Magento\Framework\UrlFactory; /** + * Catalog advanced search result + * * @deprecated CatalogSearch will be removed in 2.4, and {@see \Magento\ElasticSearch} * will replace it as the default search engine. */ class Result extends \Magento\Framework\App\Action\Action { + const DEFAULT_NO_RESULT_HANDLE = 'catalogsearch_advanced_result_noresults'; + /** * Url factory * @@ -48,13 +52,22 @@ public function __construct( } /** + * Run action + * * @return \Magento\Framework\Controller\Result\Redirect */ public function execute() { try { $this->_catalogSearchAdvanced->addFilters($this->getRequest()->getQueryValue()); - $this->_view->loadLayout(); + $size = $this->_catalogSearchAdvanced->getProductCollection()->getSize(); + + $handles = null; + if ($size == 0) { + $handles = [static::DEFAULT_NO_RESULT_HANDLE]; + } + + $this->_view->loadLayout($handles); $this->_view->renderLayout(); } catch (\Magento\Framework\Exception\LocalizedException $e) { $this->messageManager->addError($e->getMessage()); @@ -66,4 +79,14 @@ public function execute() return $resultRedirect; } } + + /** + * Returns no result handle + * + * @return string + */ + private function getNoResultsHandle() + { + return self::DEFAULT_NO_RESULT_HANDLE; + } } diff --git a/app/code/Magento/CatalogSearch/Controller/Result/Index.php b/app/code/Magento/CatalogSearch/Controller/Result/Index.php index ab796e12d81d9..3e0569ef7bfe8 100644 --- a/app/code/Magento/CatalogSearch/Controller/Result/Index.php +++ b/app/code/Magento/CatalogSearch/Controller/Result/Index.php @@ -14,11 +14,15 @@ use Magento\Search\Model\PopularSearchTerms; /** + * Catalog search result + * * @deprecated CatalogSearch will be removed in 2.4, and {@see \Magento\ElasticSearch} * will replace it as the default search engine. */ class Index extends \Magento\Framework\App\Action\Action { + const DEFAULT_NO_RESULT_HANDLE = 'catalogsearch_result_index_noresults'; + /** * Catalog session * @@ -89,12 +93,17 @@ public function execute() $getAdditionalRequestParameters = $this->getRequest()->getParams(); unset($getAdditionalRequestParameters[QueryFactory::QUERY_VAR_NAME]); + $handles = null; + if ($query->getNumResults() == 0) { + $handles = [static::DEFAULT_NO_RESULT_HANDLE]; + } + if (empty($getAdditionalRequestParameters) && $this->_objectManager->get(PopularSearchTerms::class)->isCacheable($queryText, $storeId) ) { - $this->getCacheableResult($catalogSearchHelper, $query); + $this->getCacheableResult($catalogSearchHelper, $query, $handles); } else { - $this->getNotCacheableResult($catalogSearchHelper, $query); + $this->getNotCacheableResult($catalogSearchHelper, $query, $handles); } } else { $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); @@ -106,9 +115,10 @@ public function execute() * * @param \Magento\CatalogSearch\Helper\Data $catalogSearchHelper * @param \Magento\Search\Model\Query $query + * @param array $handles * @return void */ - private function getCacheableResult($catalogSearchHelper, $query) + private function getCacheableResult($catalogSearchHelper, $query, $handles) { if (!$catalogSearchHelper->isMinQueryLength()) { $redirect = $query->getRedirect(); @@ -120,7 +130,7 @@ private function getCacheableResult($catalogSearchHelper, $query) $catalogSearchHelper->checkNotes(); - $this->_view->loadLayout(); + $this->_view->loadLayout($handles); $this->_view->renderLayout(); } @@ -129,11 +139,12 @@ private function getCacheableResult($catalogSearchHelper, $query) * * @param \Magento\CatalogSearch\Helper\Data $catalogSearchHelper * @param \Magento\Search\Model\Query $query + * @param array $handles * @return void * * @throws \Magento\Framework\Exception\LocalizedException */ - private function getNotCacheableResult($catalogSearchHelper, $query) + private function getNotCacheableResult($catalogSearchHelper, $query, $handles) { if ($catalogSearchHelper->isMinQueryLength()) { $query->setId(0)->setIsActive(1)->setIsProcessed(1); @@ -148,7 +159,7 @@ private function getNotCacheableResult($catalogSearchHelper, $query) $catalogSearchHelper->checkNotes(); - $this->_view->loadLayout(); + $this->_view->loadLayout($handles); $this->getResponse()->setNoCacheHeaders(); $this->_view->renderLayout(); } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php index 891f008979e17..d4229ff934e9b 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php @@ -27,9 +27,15 @@ function () use (&$filters, $expectedQuery) { $request = $this->createPartialMock(\Magento\Framework\App\Console\Request::class, ['getQueryValue']); $request->expects($this->once())->method('getQueryValue')->will($this->returnValue($expectedQuery)); + $collection = $this->createPartialMock( + \Magento\CatalogSearch\Model\ResourceModel\Advanced\Collection::class, + ['getSize'] + ); + $collection->expects($this->once())->method('getSize')->will($this->returnValue(1)); + $catalogSearchAdvanced = $this->createPartialMock( \Magento\CatalogSearch\Model\Advanced::class, - ['addFilters', '__wakeup'] + ['addFilters', '__wakeup', 'getProductCollection'] ); $catalogSearchAdvanced->expects($this->once())->method('addFilters')->will( $this->returnCallback( @@ -38,6 +44,8 @@ function ($added) use (&$filters) { } ) ); + $catalogSearchAdvanced->expects($this->once())->method('getProductCollection') + ->will($this->returnValue($collection)); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $context = $objectManager->getObject( @@ -138,4 +146,43 @@ public function testUrlSetOnException() ); $this->assertEquals($redirectResultMock, $instance->execute()); } + + public function testNoResultsHandle() + { + $expectedQuery = 'notExistTerm'; + + $view = $this->createPartialMock(\Magento\Framework\App\View::class, ['loadLayout', 'renderLayout']); + $view->expects($this->once())->method('loadLayout') + ->with([\Magento\CatalogSearch\Controller\Advanced\Result::DEFAULT_NO_RESULT_HANDLE]); + + $request = $this->createPartialMock(\Magento\Framework\App\Console\Request::class, ['getQueryValue']); + $request->expects($this->once())->method('getQueryValue')->will($this->returnValue($expectedQuery)); + + $collection = $this->createPartialMock( + \Magento\CatalogSearch\Model\ResourceModel\Advanced\Collection::class, + ['getSize'] + ); + $collection->expects($this->once())->method('getSize')->will($this->returnValue(0)); + + $catalogSearchAdvanced = $this->createPartialMock( + \Magento\CatalogSearch\Model\Advanced::class, + ['addFilters', '__wakeup', 'getProductCollection'] + ); + + $catalogSearchAdvanced->expects($this->once())->method('getProductCollection') + ->will($this->returnValue($collection)); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $context = $objectManager->getObject( + \Magento\Framework\App\Action\Context::class, + ['view' => $view, 'request' => $request] + ); + + /** @var \Magento\CatalogSearch\Controller\Advanced\Result $instance */ + $instance = $objectManager->getObject( + \Magento\CatalogSearch\Controller\Advanced\Result::class, + ['context' => $context, 'catalogSearchAdvanced' => $catalogSearchAdvanced] + ); + $instance->execute(); + } } From 158a0fd7a2b452d05744312bdddde287b292e494 Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Tue, 25 Sep 2018 22:05:57 +0300 Subject: [PATCH 0099/1158] Remove unused method --- .../CatalogSearch/Controller/Advanced/Result.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php index 78890643c59fb..dfbd46aa6a1cf 100644 --- a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php +++ b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php @@ -79,14 +79,4 @@ public function execute() return $resultRedirect; } } - - /** - * Returns no result handle - * - * @return string - */ - private function getNoResultsHandle() - { - return self::DEFAULT_NO_RESULT_HANDLE; - } } From caab8f7e1a1c213a7a0928b9c88f9760903ae17a Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <horytsky@adobe.com> Date: Wed, 26 Sep 2018 13:12:32 +0300 Subject: [PATCH 0100/1158] MAGETWO-95137: [2.3] Return path e-mail variable system/smtp/return_path_email doesn't work --- app/code/Magento/Email/Model/Transport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Email/Model/Transport.php b/app/code/Magento/Email/Model/Transport.php index c270c3086cca9..28d2d171eecf4 100644 --- a/app/code/Magento/Email/Model/Transport.php +++ b/app/code/Magento/Email/Model/Transport.php @@ -32,7 +32,7 @@ class Transport implements TransportInterface const XML_PATH_SENDING_RETURN_PATH_EMAIL = 'system/smtp/return_path_email'; /** - * Configuration of whether return path should be set or no. + * Whether return path should be set or no. * * Possible values are: * 0 - no From bb65b43ad9d80a34d81a0a9a409691211c9a0061 Mon Sep 17 00:00:00 2001 From: "Hakobyan, Lusine" <Lusine_Hakobyan@epam.com> Date: Wed, 26 Sep 2018 15:27:51 +0400 Subject: [PATCH 0101/1158] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Add automated test --- .../Section/AdminProductFormActionSection.xml | 1 + .../Section/AdminCreditMemoTotalSection.xml | 2 + .../Mftf/ActionGroup/AdminTaxActionGroup.xml | 7 + .../Mftf/Section/AdminConfigureTaxSection.xml | 5 + .../Section/AdminProductTaxClassSection.xml | 18 +++ .../Mftf/Test/CheckCreditMemoTotalsTest.xml | 144 ++++++++++++++++++ 6 files changed, 177 insertions(+) create mode 100644 app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml create mode 100644 app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml index afbaba41a9bb7..81ca8e1cd27f5 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml @@ -15,5 +15,6 @@ <element name="saveAndClose" type="button" selector="span[title='Save & Close']" timeout="30"/> <element name="changeStoreButton" type="button" selector="#store-change-button" timeout="10"/> <element name="selectStoreView" type="button" selector="//ul[@data-role='stores-list']/li/a[normalize-space(.)='{{var1}}']" timeout="10" parameterized="true"/> + <element name="selectTaxClass" type="select" selector="select[name='product[tax_class_id]']"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml index 00eb93452edd5..84fcc8fc47dfb 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml @@ -19,5 +19,7 @@ <element name="emailCopy" type="checkbox" selector=".order-totals-actions #send_email"/> <element name="refundStoreCredit" type="checkbox" selector=".order-totals-actions .field-refund-store-credit input[type='checkbox']"/> <element name="submitRefundOffline" type="button" selector=".order-totals-actions button[data-ui-id='order-items-submit-button']" timeout="30"/> + <element name="creditMemoItem" type="text" selector="#sales_order_view_tabs_order_creditmemos"/> + <element name="viewMemo" type="text" selector="div#sales_order_view_tabs_order_creditmemos_content a.action-menu-item"/> </section> </sections> \ No newline at end of file diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml index 6c535e3004e69..429c7dea4baa4 100644 --- a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml @@ -80,6 +80,13 @@ <see stepKey="seeSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the configuration."/> </actionGroup> + <actionGroup name="addCustomTaxRate" extends="addNewTaxRateNoZip"> + <remove keyForRemoval="fillZipCode"/> + <remove keyForRemoval="fillRate"/> + <fillField stepKey="fillZipCode" selector="{{AdminTaxRulesSection.zipCode}}" userInput="US-NY-*-Rate 2" after="fillTaxIdentifier"/> + <fillField stepKey="fillRate" selector="{{AdminTaxRulesSection.rate}}" userInput="0" after="selectCountry"/> + </actionGroup> + <!-- Action group to add a tax rate when on a tax rule configuration page --> <!-- Must already be on a tax rule configuration page or a new tax rule page --> <actionGroup name="addNewTaxRateNoZip"> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index 896d719a436ca..f3f0b7c25eef2 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -51,5 +51,10 @@ <element name="systemValueDisplayZeroTaxSales" type="checkbox" selector="#row_tax_sales_display_zero_tax input[type='checkbox']"/> <element name="dropdownDisplayZeroTaxSales" type="checkbox" selector="#row_tax_sales_display_zero_tax select"/> <element name="fixedProductTaxes" type="block" selector="#tax_weee-head" timeout="30"/> + + <element name="taxClassesCondition" type="block" selector="//a[@id='tax_classes-head' and @class='open']" timeout="30"/> + <element name="useSystemValue" type="checkbox" selector="#tax_classes_default_product_tax_class_inherit"/> + <element name="productTaxClass" type="select" selector="#tax_classes_default_product_tax_class"/> + <element name="save" type="button" selector="#save"/> </section> </sections> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml new file mode 100644 index 0000000000000..f32caf88f2133 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminProductTaxClassSection"> + <element name="additionalSettings" type="text" selector="#details-summarybase_fieldset"/> + <element name="additionalSettingsCond" type="text" selector="//summary[@id='details-summarybase_fieldset' and @aria-expanded='true']"/> + <element name="productTaxClass" type="button" selector="//div[contains(@class, 'field-tax_product_class')]//span[text()='Add New Tax Class']"/> + <element name="TaxClassName" type="block" selector="//div[contains(@class, 'field-tax_product_class')]//input[@class='mselect-input']"/> + <element name="confirm" type="button" selector="//div[contains(@class, 'field-tax_product_class')]//span[@class='mselect-save']"/> + </section> +</sections> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml new file mode 100644 index 0000000000000..1063f2aa5bf5b --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CheckCreditMemoTotalsTest"> + <annotations> + <features value="Tax"/> + <stories value="MAGETWO-91769 - Credit Memo - Wrong tax calculation! #10982"/> + <title value="Checking Credit memo Totals"/> + <description value="Checking Credit memo Totals"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95175"/> + <group value="creditMemo"/> + <group value="tax"/> + </annotations> + <before> + <!--Create category and product--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!--Create customer--> + <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> + <!--Login as admin--> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> + <!--Create tax rule and tax rate--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulePage"/> + <waitForPageLoad stepKey="waitForTaxRatePage"/> + <click stepKey="addNewTaxRate" selector="{{AdminGridMainControls.add}}"/> + <fillField stepKey="fillRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="SampleRule"/> + <actionGroup ref="addCustomTaxRate" stepKey="addCustomTaxRate"> + <argument name="taxCode" value="SimpleTaxNY"/> + </actionGroup> + <click stepKey="expandAdditionalSettings" selector="{{AdminProductTaxClassSection.additionalSettings}}"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <click selector="{{AdminProductTaxClassSection.productTaxClass}}" stepKey="ClickToAddTaxClass"/> + <fillField selector="{{AdminProductTaxClassSection.TaxClassName}}" userInput="NewTaxClass" stepKey="setName"/> + <click selector="{{AdminProductTaxClassSection.confirm}}" stepKey="ClickToDone"/> + <click stepKey="clickSave" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + <waitForPageLoad stepKey="waitForTaxRatePage1"/> + <see userInput="You saved the tax rule." stepKey="VerifyRuleSaved"/> + <!--Search and edit product to add new created tax rule--> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="OpenEditProductOnBackend"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <selectOption selector="{{AdminProductFormActionSection.selectTaxClass}}" userInput="NewTaxClass" stepKey="SetNewTaxClass" /> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + <!--Set configs--> + <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToTaxConfigPage"/> + <conditionalClick stepKey="clickOrdersInvoicesCreditSales" selector="{{AdminConfigureTaxSection.taxClasses}}" dependentSelector="{{AdminConfigureTaxSection.taxClassesCondition}}" visible="false"/> + <click selector="{{AdminConfigureTaxSection.useSystemValue}}" stepKey="UncheckUseSystemValue"/> + <selectOption selector="{{AdminConfigureTaxSection.productTaxClass}}" userInput="NewTaxClass" stepKey="selectClass"/> + <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> + <!--flash cache--> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + </before> + <after> + <!--Delete category and product--> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <!--Delete customer--> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <!--Roll Back configuration--> + <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToTaxConfigPage"/> + <conditionalClick stepKey="clickOrdersInvoicesCreditSales" selector="{{AdminConfigureTaxSection.taxClasses}}" dependentSelector="{{AdminConfigureTaxSection.taxClassesCondition}}" visible="false"/> + <selectOption selector="{{AdminConfigureTaxSection.productTaxClass}}" userInput="Taxable Goods" stepKey="selectClass"/> + <click selector="{{AdminConfigureTaxSection.useSystemValue}}" stepKey="UncheckUseSystemValue"/> + <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> + <!-- Go to the tax rule page and delete the row we created--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> + <waitForPageLoad stepKey="waitForRulesPage"/> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteRule"> + <argument name="name" value="SampleRule"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <!-- Go to the tax rate page --> + <amOnPage url="{{AdminTaxRateGridPage.url}}" stepKey="goToTaxRatesPage"/> + <waitForPageLoad stepKey="waitForRatesPage"/> + <!-- Delete tax rate that were created --> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteNYRate"> + <argument name="name" value="{{SimpleTaxNY.state}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <actionGroup ref="deleteProductTaxClass" stepKey="deleteFirstProductTaxClass"> + <argument name="taxClassName" value="NewTaxClass"/> + </actionGroup> + <!--logout--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!--Create new order--> + <actionGroup stepKey="CreateNewOrder" ref="navigateToNewOrderPageExistingCustomer"> + <argument name="customer" value="Simple_US_Customer_NY"/> + </actionGroup> + <!--Add product to order--> + <click stepKey="clickToAddProduct" selector="{{AdminOrderFormItemsSection.addProducts}}"/> + <waitForPageLoad stepKey="waitForProductsOpened"/> + <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <!--Set shipping method--> + <actionGroup stepKey="orderSelectFlatRateShipping" ref="orderSelectFlatRateShipping"/> + <!--Submit order--> + <click stepKey="SubmitOrder" selector="{{AdminOrderFormActionSection.SubmitOrder}}"/> + <waitForPageLoad stepKey="waitForPageLoad4"/> + <grabTextFrom stepKey="getOrderId" selector="|Order # (\d+)|"/> + <!--Open new created order--> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrders"/> + <waitForPageLoad stepKey="waitForPageLoad5"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$getOrderId"/> + </actionGroup> + <!--Create order invoice--> + <click selector="{{AdminDataGridTableSection.rowViewAction('1')}}" stepKey="clickCreatedOrderInGrid"/> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceAction"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage"/> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> + <see selector="{{AdminInvoiceOrderInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderProcessing"/> + <!--Create Credit Memo--> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreditMemoAction"/> + <fillField selector="{{AdminCreditMemoTotalSection.refundShipping}}" userInput="0" stepKey="setRefundShipping"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccess"/> + <click selector="{{AdminCreditMemoTotalSection.creditMemoItem}}" stepKey="goToCreatedCreditMemo"/> + <waitForPageLoad stepKey="waitForPageLoad6"/> + <!--View created memo and verify tax for product--> + <click selector="{{AdminCreditMemoTotalSection.viewMemo}}" stepKey="ViewMemo"/> + <waitForPageLoad stepKey="waitForPageLoad7"/> + <grabTextFrom selector="{{AdminCreditMemoTotalSection.grandTotal}}" stepKey="getGrandTotal"/> + <assertEquals expected='$123.00' expectedType="string" actual="($getGrandTotal)" stepKey="assertGrandTotalValue"/> + + </test> +</tests> From 77d2386c243125a31788a11e15771ee25e786993 Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Wed, 26 Sep 2018 16:18:19 +0400 Subject: [PATCH 0102/1158] MAGETWO-91602: Visual Merchandiser incorrectly displays/sorts configurable product price in Tile view - Add automated test --- .../Section/AdminCreateProductConfigurationsPanelSection.xml | 1 + .../Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml index 99e47baac37d5..7901b6f2290c9 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml @@ -35,5 +35,6 @@ <element name="applySingleQuantityToEachSkus" type="radio" selector=".admin__field-label[for='apply-single-inventory-radio']" timeout="30"/> <element name="quantity" type="input" selector="#apply-single-inventory-input"/> <element name="gridLoadingMask" type="text" selector="[data-role='spinner'][data-component*='product_attributes_listing']"/> + <element name="attributeColorCheckbox" type="select" selector="//div[contains(text(),'color') and @class='data-grid-cell-content']/../preceding-sibling::td/label/input"/> </section> </sections> diff --git a/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml b/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml index 25e03676f6870..b7ed7c05e071e 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml @@ -21,5 +21,6 @@ <element name="nthChooseColor" type="button" selector="#swatch-visual-options-panel table tbody tr:nth-of-type({{var}}) .swatch_row_name.colorpicker_handler" parameterized="true"/> <element name="nthUploadFile" type="button" selector="#swatch-visual-options-panel table tbody tr:nth-of-type({{var}}) .swatch_row_name.btn_choose_file_upload" parameterized="true"/> <element name="nthDelete" type="button" selector="#swatch-visual-options-panel table tbody tr:nth-of-type({{var}}) button.delete-option" parameterized="true"/> + <element name="deleteBtn" type="button" selector="#manage-options-panel:nth-of-type({{var}}) button.delete-option" parameterized="true"/> </section> </sections> From 3073ed5e8670ab9b095cc6fb6d29d875d4235ce2 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Wed, 26 Sep 2018 14:31:18 +0200 Subject: [PATCH 0103/1158] Shipping method set concept --- .../SetShippingMethodsOnCart.php | 105 ++++++++++++++++++ .../Magento/QuoteGraphQl/etc/schema.graphqls | 9 +- 2 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php new file mode 100644 index 0000000000000..448bdcbb37a6d --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\ShippingMethod; + +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; + +class SetShippingMethodsOnCart implements ResolverInterface +{ + /** + * @var CartRepositoryInterface + */ + private $cartRepository; + + /** + * @var MaskedQuoteIdToQuoteIdInterface + */ + private $maskedQuoteIdToQuoteId; + + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * SetShippingMethodsOnCart constructor. + * @param ArrayManager $arrayManager + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ + public function __construct( + ArrayManager $arrayManager, + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, + CartRepositoryInterface $cartRepository + ) { + $this->arrayManager = $arrayManager; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->cartRepository = $cartRepository; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $shippingMethods = $this->arrayManager->get('input/shipping_methods', $args); + $maskedCartId = $this->arrayManager->get('input/cart_id', $args); + + if (!$maskedCartId) { + // TODO: throw an exception + } + + if (!$shippingMethods) { + // TODO: throw an exception? + } + + foreach ($shippingMethods as $shippingMethod) { + if (empty($shippingMethod['cart_address_id'])) { + // TODO: throw input exception + } + + if (empty($shippingMethod['shipping_method_code'])) { + // TODO: throw input exception + } + + // TODO: move to a separate class + // TODO: check current customer can apply operations on specified cart + } + + $quoteId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); + $quote = $this->cartRepository->get($quoteId); // TODO: catch no such entity exception + $this->setShippingMethods($shippingMethods, $quote); + + $quote->collectTotals(); + $quote->save(); + //$this->cartRepository->save($quote); + + return 'Success!'; + } + + private function setShippingMethods($shippingMethods, CartInterface $quote) + { + $addresses = $quote->getAllShippingAddresses(); + /** @var \Magento\Quote\Model\Quote\Address $address */ + foreach ($addresses as $address) { + $addressId = $address->getId(); + $shippingMethodForAddress = array_search($addressId, array_column($shippingMethods, 'cart_address_id')); + if ($shippingMethodForAddress !== false) { + $address->setShippingMethod($shippingMethods[$shippingMethodForAddress]['shipping_method_code']); +// $address->setCollectShippingRates(1); + $address->save(); + } + } + // TODO: make sure that shipping method is assigned for all addresses + } +} \ No newline at end of file diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index b10575171781e..027e59c327ebd 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -11,7 +11,7 @@ type Mutation { removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput - setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput + setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ShippingMethod\\SetShippingMethodsOnCart") } input SetShippingAddressesOnCartInput { @@ -47,11 +47,12 @@ input CartAddressInput { } input SetShippingMethodsOnCartInput { + cart_id: String! shipping_methods: [ShippingMethodForAddressInput!]! } input ShippingMethodForAddressInput { - cart_address_id: String! + cart_address_id: String! # todo: int? shipping_method_code: String! } @@ -64,12 +65,12 @@ type SetShippingAddressesOnCartOutput { } type SetShippingMethodsOnCartOutput { - cart: Cart! + cart: String } # If no address is provided, the system get address assigned to a quote # If there's no address at all - the system returns all shipping methods -type AvailableShippingMethodsOnCartInput { +input AvailableShippingMethodsOnCartInput { cart_id: String! customer_address_id: Int address: CartAddressInput From a1a2b4a1368e79df8e2f8968edb63e05225daee0 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Wed, 26 Sep 2018 18:13:05 +0300 Subject: [PATCH 0104/1158] MAGETWO-91756: In Related product section add to wishlist and compare is not displaying for mobile devices portrait view - Fixed issue with missing compare/wishlist buttons on related product listings on mobile view; --- .../blank/Magento_Catalog/web/css/source/module/_listings.less | 1 - .../luma/Magento_Catalog/web/css/source/module/_listings.less | 1 - 2 files changed, 2 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less index 8b727b0d9c28d..951ca89a07988 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less @@ -63,7 +63,6 @@ } &-actions { - display: none; .actions-secondary { > button.action { diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less index d0382d34d39fc..6bf766b7400a7 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less @@ -68,7 +68,6 @@ } &-actions { - display: none; .actions-secondary { > button.action { From 476f14ff89d6be14d1b3d8c950713c00d5802ec0 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Wed, 26 Sep 2018 16:35:20 +0000 Subject: [PATCH 0105/1158] graphQl-44: refactoring of resolver Signed-off-by: vitaliyboyko <v.boyko@atwix.com> --- .../Resolver/Product/ProductTextAttribute.php | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php index 9c1212667acf3..7649464e2e1ca 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php @@ -10,8 +10,7 @@ use Magento\Catalog\Model\Product; use Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\FormatList; use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Query\Resolver\Value; -use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; @@ -25,26 +24,18 @@ class ProductTextAttribute implements ResolverInterface */ private $formatList; - /** - * @var ValueFactory - */ - private $valueFactory; - /** * @var string */ private $defaultFormat = 'html'; /** - * @param ValueFactory $valueFactory - * @param FormatList $formatFactory + * @param FormatList $formatList */ public function __construct( - ValueFactory $valueFactory, - FormatList $formatFactory + FormatList $formatList ) { - $this->valueFactory = $valueFactory; - $this->formatList = $formatFactory; + $this->formatList = $formatList; } /** @@ -56,10 +47,9 @@ public function resolve( ResolveInfo $info, array $value = null, array $args = null - ): Value { + ) { if (!isset($value['model'])) { - $result = []; - return $this->valueFactory->create($result); + throw new GraphQlInputException(__('"model" value should be specified')); } /* @var $product Product */ @@ -69,6 +59,6 @@ public function resolve( $format = $this->formatList->create($formatIdentifier); $result = ['content' => $format->getContent($product, $fieldName)]; - return $this->valueFactory->create($result); + return $result; } } From 38dbbe2b4653a6372bb68ca90686b39927614d40 Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov <isentiabov@magento.com> Date: Wed, 26 Sep 2018 15:46:24 +0300 Subject: [PATCH 0106/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - Fixed discounts deltas calculation --- .../Model/Order/Creditmemo/Total/Shipping.php | 11 ++- .../Model/Order/Creditmemo/Total/Tax.php | 13 ++-- .../Sales/Model/Order/Invoice/Total/Tax.php | 28 +++++--- .../Sales/Model/Service/CreditmemoService.php | 16 +++-- .../Model/Service/CreditmemoServiceTest.php | 70 +++++++++++-------- 5 files changed, 79 insertions(+), 59 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php index f00334f496b2a..f644d0c3a5a63 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php @@ -37,6 +37,8 @@ public function __construct( } /** + * Collects credit memo shipping totals. + * * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return $this * @throws \Magento\Framework\Exception\LocalizedException @@ -55,12 +57,10 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $orderShippingInclTax = $order->getShippingInclTax(); $orderBaseShippingInclTax = $order->getBaseShippingInclTax(); $allowedTaxAmount = $order->getShippingTaxAmount() - $order->getShippingTaxRefunded(); - $baseAllowedTaxAmount = $order->getBaseShippingTaxAmount() - $order->getBaseShippingTaxRefunded(); $allowedAmountInclTax = $allowedAmount + $allowedTaxAmount; - $baseAllowedAmountInclTax = $baseAllowedAmount + $baseAllowedTaxAmount; - - // for the credit memo - $shippingAmount = $baseShippingAmount = $shippingInclTax = $baseShippingInclTax = 0; + $baseAllowedAmountInclTax = $orderBaseShippingInclTax + - $order->getBaseShippingRefunded() + - $order->getBaseShippingTaxRefunded(); // Check if the desired shipping amount to refund was specified (from invoice or another source). if ($creditmemo->hasBaseShippingAmount()) { @@ -128,7 +128,6 @@ private function isSuppliedShippingAmountInclTax($order) /** * Get the Tax Config. - * In a future release, will become a constructor parameter. * * @return \Magento\Tax\Model\Config * diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index a842c0470ad85..5ab9469441bef 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -5,9 +5,14 @@ */ namespace Magento\Sales\Model\Order\Creditmemo\Total; +/** + * Collects credit memo taxes. + */ class Tax extends AbstractTotal { /** + * Collects credit memo taxes. + * * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return $this * @@ -79,18 +84,10 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $totalDiscountTaxCompensation += $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor; $baseTotalDiscountTaxCompensation += $invoice->getBaseShippingDiscountTaxCompensationAmnt() * $taxFactor; - $shippingDiscountTaxCompensationAmount = - $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor; - $baseShippingDiscountTaxCompensationAmount = - $invoice->getBaseShippingDiscountTaxCompensationAmnt() * $taxFactor; $shippingTaxAmount = $creditmemo->roundPrice($shippingTaxAmount); $baseShippingTaxAmount = $creditmemo->roundPrice($baseShippingTaxAmount, 'base'); $totalDiscountTaxCompensation = $creditmemo->roundPrice($totalDiscountTaxCompensation); $baseTotalDiscountTaxCompensation = $creditmemo->roundPrice($baseTotalDiscountTaxCompensation, 'base'); - $shippingDiscountTaxCompensationAmount = - $creditmemo->roundPrice($shippingDiscountTaxCompensationAmount); - $baseShippingDiscountTaxCompensationAmount = - $creditmemo->roundPrice($baseShippingDiscountTaxCompensationAmount, 'base'); if ($taxFactor < 1 && $invoice->getShippingTaxAmount() > 0) { $isPartialShippingRefunded = true; } diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php index fd5c015d9db4f..6e12f10f0c679 100644 --- a/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php @@ -5,6 +5,9 @@ */ namespace Magento\Sales\Model\Order\Invoice\Total; +/** + * Collects invoice taxes. + */ class Tax extends AbstractTotal { /** @@ -69,11 +72,24 @@ public function collect(\Magento\Sales\Model\Order\Invoice $invoice) } } + $taxDiscountCompensationAmt = $totalDiscountTaxCompensation; + $baseTaxDiscountCompensationAmt = $baseTotalDiscountTaxCompensation; + $allowedDiscountTaxCompensation = $order->getDiscountTaxCompensationAmount() - + $order->getDiscountTaxCompensationInvoiced(); + $allowedBaseDiscountTaxCompensation = $order->getBaseDiscountTaxCompensationAmount() - + $order->getBaseDiscountTaxCompensationInvoiced(); + if ($this->_canIncludeShipping($invoice)) { $totalTax += $order->getShippingTaxAmount(); $baseTotalTax += $order->getBaseShippingTaxAmount(); $totalDiscountTaxCompensation += $order->getShippingDiscountTaxCompensationAmount(); $baseTotalDiscountTaxCompensation += $order->getBaseShippingDiscountTaxCompensationAmnt(); + + $allowedDiscountTaxCompensation += $order->getShippingDiscountTaxCompensationAmount() - + $order->getShippingDiscountTaxCompensationInvoiced(); + $allowedBaseDiscountTaxCompensation += $order->getBaseShippingDiscountTaxCompensationAmnt() - + $order->getBaseShippingDiscountTaxCompensationInvoiced(); + $invoice->setShippingTaxAmount($order->getShippingTaxAmount()); $invoice->setBaseShippingTaxAmount($order->getBaseShippingTaxAmount()); $invoice->setShippingDiscountTaxCompensationAmount($order->getShippingDiscountTaxCompensationAmount()); @@ -81,14 +97,6 @@ public function collect(\Magento\Sales\Model\Order\Invoice $invoice) } $allowedTax = $order->getTaxAmount() - $order->getTaxInvoiced(); $allowedBaseTax = $order->getBaseTaxAmount() - $order->getBaseTaxInvoiced(); - $allowedDiscountTaxCompensation = $order->getDiscountTaxCompensationAmount() + - $order->getShippingDiscountTaxCompensationAmount() - - $order->getDiscountTaxCompensationInvoiced() - - $order->getShippingDiscountTaxCompensationInvoiced(); - $allowedBaseDiscountTaxCompensation = $order->getBaseDiscountTaxCompensationAmount() + - $order->getBaseShippingDiscountTaxCompensationAmnt() - - $order->getBaseDiscountTaxCompensationInvoiced() - - $order->getBaseShippingDiscountTaxCompensationInvoiced(); if ($invoice->isLast()) { $totalTax = $allowedTax; @@ -107,8 +115,8 @@ public function collect(\Magento\Sales\Model\Order\Invoice $invoice) $invoice->setTaxAmount($totalTax); $invoice->setBaseTaxAmount($baseTotalTax); - $invoice->setDiscountTaxCompensationAmount($totalDiscountTaxCompensation); - $invoice->setBaseDiscountTaxCompensationAmount($baseTotalDiscountTaxCompensation); + $invoice->setDiscountTaxCompensationAmount($taxDiscountCompensationAmt); + $invoice->setBaseDiscountTaxCompensationAmount($baseTaxDiscountCompensationAmt); $invoice->setGrandTotal($invoice->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation); $invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() + $baseTotalTax + $baseTotalDiscountTaxCompensation); diff --git a/app/code/Magento/Sales/Model/Service/CreditmemoService.php b/app/code/Magento/Sales/Model/Service/CreditmemoService.php index e8f2e6e5305f7..a1bff966753f0 100644 --- a/app/code/Magento/Sales/Model/Service/CreditmemoService.php +++ b/app/code/Magento/Sales/Model/Service/CreditmemoService.php @@ -178,6 +178,8 @@ public function refund( } /** + * Checks if credit memo is available for refund. + * * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo * @return bool * @throws \Magento\Framework\Exception\LocalizedException @@ -200,7 +202,7 @@ protected function validateForRefund(\Magento\Sales\Api\Data\CreditmemoInterface throw new \Magento\Framework\Exception\LocalizedException( __( 'The most money available to refund is %1.', - $creditmemo->getOrder()->formatBasePrice($baseAvailableRefund) + $creditmemo->getOrder()->formatPriceTxt($baseAvailableRefund) ) ); } @@ -208,8 +210,9 @@ protected function validateForRefund(\Magento\Sales\Api\Data\CreditmemoInterface } /** - * @return \Magento\Sales\Model\Order\RefundAdapterInterface + * Initializes RefundAdapterInterface dependency. * + * @return \Magento\Sales\Model\Order\RefundAdapterInterface * @deprecated 100.1.3 */ private function getRefundAdapter() @@ -222,8 +225,9 @@ private function getRefundAdapter() } /** - * @return \Magento\Framework\App\ResourceConnection|mixed + * Initializes ResourceConnection dependency. * + * @return \Magento\Framework\App\ResourceConnection|mixed * @deprecated 100.1.3 */ private function getResource() @@ -236,8 +240,9 @@ private function getResource() } /** - * @return \Magento\Sales\Api\OrderRepositoryInterface + * Initializes OrderRepositoryInterface dependency. * + * @return \Magento\Sales\Api\OrderRepositoryInterface * @deprecated 100.1.3 */ private function getOrderRepository() @@ -250,8 +255,9 @@ private function getOrderRepository() } /** - * @return \Magento\Sales\Api\InvoiceRepositoryInterface + * Initializes InvoiceRepositoryInterface dependency. * + * @return \Magento\Sales\Api\InvoiceRepositoryInterface * @deprecated 100.1.3 */ private function getInvoiceRepository() 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 2e668f0b0d6f1..68681c6c5a66b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Service/CreditmemoServiceTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Service/CreditmemoServiceTest.php @@ -3,10 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Test\Unit\Model\Service; use Magento\Sales\Model\Order; +use Magento\Sales\Api\Data\CreditmemoInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + /** * Class CreditmemoServiceTest * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -14,34 +19,34 @@ class CreditmemoServiceTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Sales\Api\CreditmemoRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Sales\Api\CreditmemoRepositoryInterface|MockObject */ protected $creditmemoRepositoryMock; /** - * @var \Magento\Sales\Api\CreditmemoCommentRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Sales\Api\CreditmemoCommentRepositoryInterface|MockObject */ protected $creditmemoCommentRepositoryMock; /** - * @var \Magento\Framework\Api\SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Api\SearchCriteriaBuilder|MockObject */ protected $searchCriteriaBuilderMock; /** - * @var \Magento\Framework\Api\FilterBuilder|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Api\FilterBuilder|MockObject */ protected $filterBuilderMock; /** - * @var \Magento\Sales\Model\Order\CreditmemoNotifier|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Sales\Model\Order\CreditmemoNotifier|MockObject */ protected $creditmemoNotifierMock; /** - * @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Pricing\PriceCurrencyInterface|MockObject */ - private $priceCurrencyMock; + private $priceCurrency; /** * @var \Magento\Sales\Model\Service\CreditmemoService @@ -79,7 +84,7 @@ protected function setUp() ['setField', 'setValue', 'setConditionType', 'create'] ); $this->creditmemoNotifierMock = $this->createMock(\Magento\Sales\Model\Order\CreditmemoNotifier::class); - $this->priceCurrencyMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class) + $this->priceCurrency = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class) ->getMockForAbstractClass(); $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -91,7 +96,7 @@ protected function setUp() 'searchCriteriaBuilder' => $this->searchCriteriaBuilderMock, 'filterBuilder' => $this->filterBuilderMock, 'creditmemoNotifier' => $this->creditmemoNotifierMock, - 'priceCurrency' => $this->priceCurrencyMock, + 'priceCurrency' => $this->priceCurrency, ] ); } @@ -187,7 +192,7 @@ public function testRefund() $orderMock->expects($this->once())->method('getBaseTotalPaid')->willReturn(10); $creditMemoMock->expects($this->once())->method('getBaseGrandTotal')->willReturn(10); - $this->priceCurrencyMock->expects($this->any()) + $this->priceCurrency->expects($this->any()) ->method('round') ->willReturnArgument(0); @@ -259,7 +264,7 @@ public function testRefundPendingCreditMemo() $orderMock->expects($this->once())->method('getBaseTotalPaid')->willReturn(10); $creditMemoMock->expects($this->once())->method('getBaseGrandTotal')->willReturn(10); - $this->priceCurrencyMock->expects($this->any()) + $this->priceCurrency->expects($this->any()) ->method('round') ->willReturnArgument(0); @@ -324,27 +329,32 @@ public function testRefundExpectsMoneyAvailableToReturn() $baseGrandTotal = 10; $baseTotalRefunded = 9; $baseTotalPaid = 10; - $creditMemoMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoInterface::class) - ->setMethods(['getId', 'getOrder', 'formatBasePrice']) + /** @var CreditmemoInterface|MockObject $creditMemo */ + $creditMemo = $this->getMockBuilder(CreditmemoInterface::class) + ->setMethods(['getId', 'getOrder']) ->getMockForAbstractClass(); - $creditMemoMock->expects($this->once())->method('getId')->willReturn(null); - $orderMock = $this->getMockBuilder(Order::class)->disableOriginalConstructor()->getMock(); - $creditMemoMock->expects($this->atLeastOnce())->method('getOrder')->willReturn($orderMock); - $creditMemoMock->expects($this->once())->method('getBaseGrandTotal')->willReturn($baseGrandTotal); - $orderMock->expects($this->atLeastOnce())->method('getBaseTotalRefunded')->willReturn($baseTotalRefunded); - $this->priceCurrencyMock->expects($this->exactly(2))->method('round')->withConsecutive( - [$baseTotalRefunded + $baseGrandTotal], - [$baseTotalPaid] - )->willReturnOnConsecutiveCalls( - $baseTotalRefunded + $baseGrandTotal, - $baseTotalPaid - ); - $orderMock->expects($this->atLeastOnce())->method('getBaseTotalPaid')->willReturn($baseTotalPaid); + $creditMemo->method('getId') + ->willReturn(null); + /** @var Order|MockObject $order */ + $order = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->getMock(); + $creditMemo->method('getOrder') + ->willReturn($order); + $creditMemo->method('getBaseGrandTotal') + ->willReturn($baseGrandTotal); + $order->method('getBaseTotalRefunded') + ->willReturn($baseTotalRefunded); + $this->priceCurrency->method('round') + ->withConsecutive([$baseTotalRefunded + $baseGrandTotal], [$baseTotalPaid]) + ->willReturnOnConsecutiveCalls($baseTotalRefunded + $baseGrandTotal, $baseTotalPaid); + $order->method('getBaseTotalPaid') + ->willReturn($baseTotalPaid); $baseAvailableRefund = $baseTotalPaid - $baseTotalRefunded; - $orderMock->expects($this->once())->method('formatBasePrice')->with( - $baseAvailableRefund - )->willReturn($baseAvailableRefund); - $this->creditmemoService->refund($creditMemoMock, true); + $order->method('formatPriceTxt') + ->with($baseAvailableRefund) + ->willReturn($baseAvailableRefund); + $this->creditmemoService->refund($creditMemo, true); } /** From 1c9295788e084da5ba748474d0170c555f8de82f Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Thu, 27 Sep 2018 13:52:04 +0300 Subject: [PATCH 0107/1158] MAGETWO-91785: Fixed incorrect order returns request flow --- .../Magento/Sales/Controller/AbstractController/Reorder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index 2cd031c9f1f6e..65cb537e89fec 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -11,7 +11,7 @@ use Magento\Framework\App\Action\HttpPostActionInterface; /** - * Class Reorder + * Abstract class for controllers Reorder(Customer) and Reorder(Guest) * * @package Magento\Sales\Controller\AbstractController */ From bba7e3525d99eca28f3966af6732b7b41ae01493 Mon Sep 17 00:00:00 2001 From: "Hakobyan, Lusine" <Lusine_Hakobyan@epam.com> Date: Thu, 27 Sep 2018 15:10:36 +0400 Subject: [PATCH 0108/1158] MAGETWO-91733: Unusual behavior with the persistent shopping cart after the session is expired - Add automated test --- ...ingCartBehaviorAfterSessionExpiredTest.xml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 app/code/Magento/Persistent/Test/Mftf/Test/CheckShoppingCartBehaviorAfterSessionExpiredTest.xml diff --git a/app/code/Magento/Persistent/Test/Mftf/Test/CheckShoppingCartBehaviorAfterSessionExpiredTest.xml b/app/code/Magento/Persistent/Test/Mftf/Test/CheckShoppingCartBehaviorAfterSessionExpiredTest.xml new file mode 100644 index 0000000000000..c66a2979aa7f5 --- /dev/null +++ b/app/code/Magento/Persistent/Test/Mftf/Test/CheckShoppingCartBehaviorAfterSessionExpiredTest.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CheckShoppingCartBehaviorAfterSessionExpiredTest"> + <annotations> + <features value="Persistent"/> + <stories value="MAGETWO-91733 - Unusual behavior with the persistent shopping cart after the session is expired"/> + <title value="Checking behavior with the persistent shopping cart after the session is expired"/> + <description value="Checking behavior with the persistent shopping cart after the session is expired"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95118"/> + <group value="persistent"/> + </annotations> + <before> + <!--Enable Persistence--> + <createData entity="PersistentConfigEnabled" stepKey="enablePersistent"/> + <!--Create product--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!-- Create new customer --> + <actionGroup ref="SignUpNewUserFromStorefrontActionGroup" stepKey="SignUpNewUser"> + <argument name="Customer" value="Simple_US_Customer_NY"/> + </actionGroup> + <!--Add shipping information--> + <actionGroup ref="EnterCustomerAddressInfo" stepKey="enterAddressInfo"> + <argument name="Address" value="US_Address_NY"/> + </actionGroup> + </before> + <after> + <!--Roll back configuration--> + <createData entity="PersistentConfigDefault" stepKey="setDefaultPersistentState"/> + <!--Delete product--> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + </after> + <!-- Add simple product to cart --> + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart1"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToShoppingCartFromMinicart"/> + <!--Reset cookies and refresh the page--> + <resetCookie userInput="PHPSESSID" stepKey="resetCookieForCart"/> + <reloadPage stepKey="reloadPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <!--Check product exists in cart--> + <see userInput="$$createProduct.name$$" stepKey="ProductExistsInCart"/> + </test> +</tests> From 1beb99d37ddec7112105303bd98ac8c340ff0d7b Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Thu, 27 Sep 2018 14:28:13 +0300 Subject: [PATCH 0109/1158] MAGETWO-59789: Image Swatch size change not working - Add swatch image config size --- .../Swatches/view/frontend/web/js/swatch-renderer.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index 853eba3c98df2..802260f0a4085 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -501,7 +501,9 @@ define([ label, width, height, - attr; + attr, + swatchImageWidth, + swatchImageHeight; if (!optionConfig.hasOwnProperty(this.id)) { return ''; @@ -534,6 +536,9 @@ define([ ' thumb-width="' + width + '"' + ' thumb-height="' + height + '"'; + swatchImageWidth = _.has(sizeConfig, 'swatchImage') ? sizeConfig.swatchImage.width : 30; + swatchImageHeight = _.has(sizeConfig, 'swatchImage') ? sizeConfig.swatchImage.height : 20; + if (!this.hasOwnProperty('products') || this.products.length <= 0) { attr += ' option-empty="true"'; } @@ -552,7 +557,7 @@ define([ // Image html += '<div class="' + optionClass + ' image" ' + attr + ' style="background: url(' + value + ') no-repeat center; background-size: initial;width:' + - sizeConfig.swatchImage.width + 'px; height:' + sizeConfig.swatchImage.height + 'px">' + '' + + swatchImageWidth + 'px; height:' + swatchImageHeight + 'px">' + '' + '</div>'; } else if (type === 3) { // Clear From 5d5ae032b48280118d8681a30d9d4abd1d2027fb Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Thu, 27 Sep 2018 15:16:51 +0300 Subject: [PATCH 0110/1158] MAGETWO-91679: Bundled SKUs are being assembled based on the product ID number - Fixed an issue with incorrect genereation of dynamic SKU for bundle products; --- app/code/Magento/Bundle/Model/Product/Type.php | 7 +++++-- .../Bundle/Test/Unit/Model/Product/TypeTest.php | 11 +++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index 92bada8094c7e..67441cd944c4f 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -308,8 +308,11 @@ public function getSku($product) $selectionIds = $this->serializer->unserialize($customOption->getValue()); if (!empty($selectionIds)) { $selections = $this->getSelectionsByIds($selectionIds, $product); - foreach ($selections->getItems() as $selection) { - $skuParts[] = $selection->getSku(); + foreach ($selectionIds as $selectionId) { + $entity = $selections->getItemByColumnValue('selection_id', $selectionId); + if ($entity->getEntityId()) { + $skuParts[] = $entity->getSku(); + } } } } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php index 4bbf5641c55d3..1b9cafbe8c198 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php @@ -1595,7 +1595,7 @@ public function testGetSkuWithoutType() ->disableOriginalConstructor() ->getMock(); $selectionItemMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->setMethods(['getSku', '__wakeup']) + ->setMethods(['getSku', 'getEntityId', '__wakeup']) ->disableOriginalConstructor() ->getMock(); @@ -1623,9 +1623,12 @@ public function testGetSkuWithoutType() ->will($this->returnValue($serializeIds)); $selectionMock = $this->getSelectionsByIdsMock($selectionIds, $productMock, 5, 6); $selectionMock->expects(($this->any())) - ->method('getItems') - ->will($this->returnValue([$selectionItemMock])); - $selectionItemMock->expects($this->any()) + ->method('getItemByColumnValue') + ->will($this->returnValue($selectionItemMock)); + $selectionItemMock->expects($this->at(0)) + ->method('getEntityId') + ->will($this->returnValue(1)); + $selectionItemMock->expects($this->once()) ->method('getSku') ->will($this->returnValue($itemSku)); From 27474ec6be80104d0b78231719610dacc5de7f2b Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Tue, 25 Sep 2018 15:17:21 +0300 Subject: [PATCH 0111/1158] MAGETWO-91764: Frontend base url https results in admin too many redirects #8800 - Fixed an issue with cyclic redirects when using 'custom admin url' and 'secure urls in admin'. --- .../Magento/Backend/Model/AdminPathConfig.php | 38 ++++++++-------- .../Test/Unit/Model/AdminPathConfigTest.php | 44 +++++++++++++------ 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Backend/Model/AdminPathConfig.php b/app/code/Magento/Backend/Model/AdminPathConfig.php index e7338adca4a2a..0e77835a5134c 100644 --- a/app/code/Magento/Backend/Model/AdminPathConfig.php +++ b/app/code/Magento/Backend/Model/AdminPathConfig.php @@ -48,10 +48,7 @@ public function __construct( } /** - * {@inheritdoc} - * - * @param \Magento\Framework\App\RequestInterface $request - * @return string + * @inheritdoc */ public function getCurrentSecureUrl(\Magento\Framework\App\RequestInterface $request) { @@ -59,28 +56,29 @@ public function getCurrentSecureUrl(\Magento\Framework\App\RequestInterface $req } /** - * {@inheritdoc} - * - * @param string $path - * @return bool + * @inheritdoc */ public function shouldBeSecure($path) { - return parse_url( - (string)$this->coreConfig->getValue(Store::XML_PATH_UNSECURE_BASE_URL, 'default'), - PHP_URL_SCHEME - ) === 'https' - || $this->backendConfig->isSetFlag(Store::XML_PATH_SECURE_IN_ADMINHTML) - && parse_url( - (string)$this->coreConfig->getValue(Store::XML_PATH_SECURE_BASE_URL, 'default'), - PHP_URL_SCHEME - ) === 'https'; + $baseUrl = (string)$this->coreConfig->getValue(Store::XML_PATH_UNSECURE_BASE_URL, 'default'); + if (parse_url($baseUrl, PHP_URL_SCHEME) === 'https') { + return true; + } + + if ($this->backendConfig->isSetFlag(Store::XML_PATH_SECURE_IN_ADMINHTML)) { + if ($this->backendConfig->isSetFlag('admin/url/use_custom')) { + $adminBaseUrl = (string)$this->coreConfig->getValue('admin/url/custom', 'default'); + } else { + $adminBaseUrl = (string)$this->coreConfig->getValue(Store::XML_PATH_SECURE_BASE_URL, 'default'); + } + return parse_url($adminBaseUrl, PHP_URL_SCHEME) === 'https'; + } + + return false; } /** - * {@inheritdoc} - * - * @return string + * @inheritdoc */ public function getDefaultPath() { diff --git a/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php b/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php index 4911dc1e9968e..b373459b7864d 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php @@ -76,17 +76,35 @@ public function testGetCurrentSecureUrl() * @param $unsecureBaseUrl * @param $useSecureInAdmin * @param $secureBaseUrl + * @param $useCustomUrl + * @param $customUrl * @param $expected * @dataProvider shouldBeSecureDataProvider */ - public function testShouldBeSecure($unsecureBaseUrl, $useSecureInAdmin, $secureBaseUrl, $expected) - { - $coreConfigValueMap = [ + public function testShouldBeSecure( + $unsecureBaseUrl, + $useSecureInAdmin, + $secureBaseUrl, + $useCustomUrl, + $customUrl, + $expected + ) { + $coreConfigValueMap = $this->returnValueMap([ [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, 'default', null, $unsecureBaseUrl], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, 'default', null, $secureBaseUrl], - ]; - $this->coreConfig->expects($this->any())->method('getValue')->will($this->returnValueMap($coreConfigValueMap)); - $this->backendConfig->expects($this->any())->method('isSetFlag')->willReturn($useSecureInAdmin); + ['admin/url/custom', 'default', null, $customUrl], + ]); + $backendConfigFlagsMap = $this->returnValueMap([ + [\Magento\Store\Model\Store::XML_PATH_SECURE_IN_ADMINHTML, $useSecureInAdmin], + ['admin/url/use_custom', $useCustomUrl], + ]); + $this->coreConfig->expects($this->atLeast(1))->method('getValue') + ->will($coreConfigValueMap); + $this->coreConfig->expects($this->atMost(2))->method('getValue') + ->will($coreConfigValueMap); + + $this->backendConfig->expects($this->atMost(2))->method('isSetFlag') + ->will($backendConfigFlagsMap); $this->assertEquals($expected, $this->adminPathConfig->shouldBeSecure('')); } @@ -96,13 +114,13 @@ public function testShouldBeSecure($unsecureBaseUrl, $useSecureInAdmin, $secureB public function shouldBeSecureDataProvider() { return [ - ['http://localhost/', false, 'default', false], - ['http://localhost/', true, 'default', false], - ['https://localhost/', false, 'default', true], - ['https://localhost/', true, 'default', true], - ['http://localhost/', false, 'https://localhost/', false], - ['http://localhost/', true, 'https://localhost/', true], - ['https://localhost/', true, 'https://localhost/', true], + ['http://localhost/', false, 'default', false, '', false], + ['http://localhost/', true, 'default', false, '', false], + ['https://localhost/', false, 'default', false, '', true], + ['https://localhost/', true, 'default', false, '', true], + ['http://localhost/', false, 'https://localhost/', false, '', false], + ['http://localhost/', true, 'https://localhost/', false, '', true], + ['https://localhost/', true, 'https://localhost/', false, '', true], ]; } From 32058c748731348e7d38cffa7a6c56113e17b3d8 Mon Sep 17 00:00:00 2001 From: David Alger <davidmalger@gmail.com> Date: Thu, 27 Sep 2018 10:44:27 -0500 Subject: [PATCH 0112/1158] Update colinmollenhour/cache-backend-redis from version 1.10.5 to 1.10.6 See colinmollenhour/Cm_Cache_Backend_Redis#134 for details on updates to library --- composer.json | 2 +- composer.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index e2a646275d98b..dfd7bfb5aa9ec 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "lib-libxml": "*", "braintree/braintree_php": "3.35.0", "colinmollenhour/cache-backend-file": "~1.4.1", - "colinmollenhour/cache-backend-redis": "1.10.5", + "colinmollenhour/cache-backend-redis": "1.10.6", "colinmollenhour/credis": "1.10.0", "colinmollenhour/php-redis-session-abstract": "~1.4.0", "composer/composer": "^1.6", diff --git a/composer.lock b/composer.lock index 2550f70f0be81..849366434dbf4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "18982aa4d36bcfd22cf073dfb578efdb", + "content-hash": "dcecc6ef5197bb32c59c7ba1f5d136ac", "packages": [ { "name": "braintree/braintree_php", @@ -88,16 +88,16 @@ }, { "name": "colinmollenhour/cache-backend-redis", - "version": "1.10.5", + "version": "1.10.6", "source": { "type": "git", "url": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis.git", - "reference": "91d949e28d939e607484a4bbf9307cff5afa689b" + "reference": "cc941a5f4cc017e11d3eab9061811ba9583ed6bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/Cm_Cache_Backend_Redis/zipball/91d949e28d939e607484a4bbf9307cff5afa689b", - "reference": "91d949e28d939e607484a4bbf9307cff5afa689b", + "url": "https://api.github.com/repos/colinmollenhour/Cm_Cache_Backend_Redis/zipball/cc941a5f4cc017e11d3eab9061811ba9583ed6bf", + "reference": "cc941a5f4cc017e11d3eab9061811ba9583ed6bf", "shasum": "" }, "require": { @@ -120,7 +120,7 @@ ], "description": "Zend_Cache backend using Redis with full support for tags.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis", - "time": "2018-05-15T16:02:25+00:00" + "time": "2018-09-24T16:02:07+00:00" }, { "name": "colinmollenhour/credis", From 5aab5421697039e56993f84d88e2b6db4a2242da Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Wed, 26 Sep 2018 21:12:12 +0300 Subject: [PATCH 0113/1158] MAGETWO-91517: Cancel and Return link removes billing and shipping address - Provide information from database to set to browser local storage if local storage is empty. --- .../Checkout/Model/DefaultConfigProvider.php | 53 +++++++++++++++++-- .../web/js/model/checkout-data-resolver.js | 13 ++++- .../web/js/view/form/element/email.js | 7 +++ 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php index ea6cdd2e51b4a..fd120f0a37a4b 100644 --- a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php +++ b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php @@ -14,6 +14,7 @@ use Magento\Customer\Model\Session as CustomerSession; use Magento\Customer\Model\Url as CustomerUrlManager; use Magento\Eav\Api\AttributeOptionManagementInterface; +use Magento\Framework\Api\CustomAttributesDataInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Http\Context as HttpContext; use Magento\Framework\App\ObjectManager; @@ -22,9 +23,11 @@ use Magento\Framework\UrlInterface; use Magento\Quote\Api\CartItemRepositoryInterface as QuoteItemRepository; use Magento\Quote\Api\CartTotalRepositoryInterface; +use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\ShippingMethodManagementInterface as ShippingMethodManager; use Magento\Quote\Model\QuoteIdMaskFactory; use Magento\Store\Model\ScopeInterface; +use Magento\Ui\Component\Form\Element\Multiline; /** * Default Config Provider @@ -272,16 +275,28 @@ public function __construct( * * @return array|mixed * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\LocalizedException */ public function getConfig() { - $quoteId = $this->checkoutSession->getQuote()->getId(); + $quote = $this->checkoutSession->getQuote(); + $quoteId = $quote->getId(); + $email = $quote->getShippingAddress()->getEmail(); $output['formKey'] = $this->formKey->getFormKey(); $output['customerData'] = $this->getCustomerData(); $output['quoteData'] = $this->getQuoteData(); $output['quoteItemData'] = $this->getQuoteItemData(); $output['isCustomerLoggedIn'] = $this->isCustomerLoggedIn(); $output['selectedShippingMethod'] = $this->getSelectedShippingMethod(); + if ($email && !$this->isCustomerLoggedIn()) { + $shippingAddressFromData = $this->getAddressFromData($quote->getShippingAddress()); + $billingAddressFromData = $this->getAddressFromData($quote->getBillingAddress()); + $output['shippingAddressFromData'] = $shippingAddressFromData; + if ($shippingAddressFromData != $billingAddressFromData) { + $output['billingAddressFromData'] = $billingAddressFromData; + } + $output['validatedEmailValue'] = $email; + } $output['storeCode'] = $this->getStoreCode(); $output['isGuestCheckoutAllowed'] = $this->isGuestCheckoutAllowed(); $output['isCustomerLoginRequired'] = $this->isCustomerLoginRequired(); @@ -293,11 +308,11 @@ public function getConfig() $output['staticBaseUrl'] = $this->getStaticBaseUrl(); $output['priceFormat'] = $this->localeFormat->getPriceFormat( null, - $this->checkoutSession->getQuote()->getQuoteCurrencyCode() + $quote->getQuoteCurrencyCode() ); $output['basePriceFormat'] = $this->localeFormat->getPriceFormat( null, - $this->checkoutSession->getQuote()->getBaseCurrencyCode() + $quote->getBaseCurrencyCode() ); $output['postCodes'] = $this->postCodesConfig->getPostCodes(); $output['imageData'] = $this->imageProvider->getImages($quoteId); @@ -528,6 +543,38 @@ private function getSelectedShippingMethod() return $shippingMethodData; } + /** + * Create address data appropriate to fill checkout address form + * + * @param AddressInterface $address + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function getAddressFromData(AddressInterface $address) + { + $addressData = []; + $attributesMetadata = $this->addressMetadata->getAllAttributesMetadata(); + foreach ($attributesMetadata as $attributeMetadata) { + if (!$attributeMetadata->isVisible()) { + continue; + } + $attributeCode = $attributeMetadata->getAttributeCode(); + $attributeData = $address->getData($attributeCode); + if ($attributeData) { + if ($attributeMetadata->getFrontendInput() === Multiline::NAME) { + $attributeData = \is_array($attributeData) ? $attributeData : explode("\n", $attributeData); + $attributeData = (object)$attributeData; + } + if ($attributeMetadata->isUserDefined()) { + $addressData[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES][$attributeCode] = $attributeData; + continue; + } + $addressData[$attributeCode] = $attributeData; + } + } + return $addressData; + } + /** * Retrieve store code * diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js index 73f4df567903c..25abe3c4ed3a0 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js @@ -60,13 +60,18 @@ define([ this.resolveBillingAddress(); } } - }, /** * Resolve shipping address. Used local storage */ resolveShippingAddress: function () { + if (!checkoutData.getShippingAddressFromData() && + window.checkoutConfig.shippingAddressFromData + ) { + checkoutData.setShippingAddressFromData(window.checkoutConfig.shippingAddressFromData); + } + var newCustomerShippingAddress = checkoutData.getNewCustomerShippingAddress(); if (newCustomerShippingAddress) { @@ -196,6 +201,12 @@ define([ * Resolve billing address. Used local storage */ resolveBillingAddress: function () { + if (!checkoutData.getBillingAddressFromData() && + window.checkoutConfig.billingAddressFromData + ) { + checkoutData.setBillingAddressFromData(window.checkoutConfig.billingAddressFromData); + } + var selectedBillingAddress = checkoutData.getSelectedBillingAddress(), newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress(); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js index 4a25778e754c7..6c0075fca6d51 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js @@ -17,6 +17,13 @@ define([ ], function ($, Component, ko, customer, checkEmailAvailability, loginAction, quote, checkoutData, fullScreenLoader) { 'use strict'; + if (!checkoutData.getValidatedEmailValue() && + window.checkoutConfig.validatedEmailValue + ) { + checkoutData.setInputFieldEmailValue(window.checkoutConfig.validatedEmailValue); + checkoutData.setValidatedEmailValue(window.checkoutConfig.validatedEmailValue); + } + var validatedEmail = checkoutData.getValidatedEmailValue(); if (validatedEmail && !customer.isLoggedIn()) { From 77ec759a758eb80aceb28a67ab65d46846e38d78 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Thu, 27 Sep 2018 21:14:23 +0300 Subject: [PATCH 0114/1158] MAGETWO-91640: Scheduled Import of Products fails on error when errors should be skipped - Changed behaviour for "skip-errors" processing during import shceduling --- .../CatalogImportExport/Model/Import/Product.php | 7 +++++-- app/code/Magento/ImportExport/Model/Import.php | 13 +++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index b755d91e403ff..d85c64327be60 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1623,8 +1623,11 @@ protected function _saveProducts() continue; } if ($this->getErrorAggregator()->hasToBeTerminated()) { - $this->getErrorAggregator()->addRowToSkip($rowNum); - continue; + $validationStrategy = $this->_parameters[Import::FIELD_NAME_VALIDATION_STRATEGY]; + if (ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS !== $validationStrategy) { + $this->getErrorAggregator()->addRowToSkip($rowNum); + continue; + } } $rowScope = $this->getRowScope($rowData); diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index b5e8220e0e9b0..064c696ad0a84 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -181,7 +181,7 @@ class Import extends \Magento\ImportExport\Model\AbstractModel * @param Source\Import\Behavior\Factory $behaviorFactory * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry * @param History $importHistoryModel - * @param \Magento\Framework\Stdlib\DateTime\DateTime + * @param \Magento\Framework\Stdlib\DateTime\DateTime $localeDate * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -443,6 +443,8 @@ public function importSource() } /** + * Processing of import. + * * @return bool * @throws \Magento\Framework\Exception\LocalizedException */ @@ -462,6 +464,8 @@ public function isImportAllowed() } /** + * Get error aggregator instance. + * * @return ProcessingErrorAggregatorInterface * @throws \Magento\Framework\Exception\LocalizedException */ @@ -585,6 +589,11 @@ public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource $this->addLogComment($messages); $result = !$errorAggregator->getErrorsCount(); + $validationStrategy = $this->getData(self::FIELD_NAME_VALIDATION_STRATEGY); + if ($validationStrategy === ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS) { + $result = true; + } + if ($result) { $this->addLogComment(__('Import data validation is complete.')); } @@ -710,9 +719,9 @@ public function isReportEntityType($entity = null) /** * Create history report * + * @param string $sourceFileRelative * @param string $entity * @param string $extension - * @param string $sourceFileRelative * @param array $result * @return $this * @throws \Magento\Framework\Exception\LocalizedException From 312449eb5672f67dd09f6804f1ddd61e714069d2 Mon Sep 17 00:00:00 2001 From: Aleksey Tsoy <aleksey_tsoy@epam.com> Date: Fri, 28 Sep 2018 13:27:10 +0600 Subject: [PATCH 0115/1158] MAGETWO-91649: #13513: Magento ignore store-level url_key of child category in URL rewrite process for global scope - Added automated test --- .../ActionGroup/AdminCategoryActionGroup.xml | 24 ++++++- .../StorefrontCategoryActionGroup.xml | 15 +++++ ...iteStoreLevelUrlKeyOfChildCategoryTest.xml | 67 +++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/RewriteStoreLevelUrlKeyOfChildCategoryTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml index 7c04e9bd83d56..b5b69cefff9a6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml @@ -237,8 +237,30 @@ </arguments> <amOnPage url="{{AdminCategoryPage.page}}" stepKey="amOnCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(Category.Name)}}" stepKey="navigateToCreatedCategory" /> + <click selector="{{AdminCategorySidebarTreeSection.expandAll}}" stepKey="expandAll"/> <waitForPageLoad stepKey="waitForPageLoad2"/> + <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(Category.Name)}}" stepKey="navigateToCreatedCategory" /> <waitForLoadingMaskToDisappear stepKey="waitForSpinner" /> </actionGroup> + + <actionGroup name="ChangeSeoUrlKey"> + <arguments> + <argument name="value" type="string"/> + </arguments> + <click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="openSeoSection"/> + <fillField selector="{{AdminCategorySEOSection.UrlKeyInput}}" userInput="{{value}}" stepKey="enterURLKey"/> + <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategory"/> + <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="assertSuccessMessage"/> + </actionGroup> + + <actionGroup name="ChangeSeoUrlKeyForSubCategory"> + <arguments> + <argument name="value" type="string"/> + </arguments> + <click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="openSeoSection"/> + <uncheckOption selector="{{AdminCategorySEOSection.UrlKeyDefaultValueCheckbox}}" stepKey="uncheckDefaultValue"/> + <fillField selector="{{AdminCategorySEOSection.UrlKeyInput}}" userInput="{{value}}" stepKey="enterURLKey"/> + <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategory"/> + <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="assertSuccessMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml index 4376e78242fbd..a8256b2d55937 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml @@ -50,4 +50,19 @@ <click selector="{{StorefrontCategoryMainSection.modeListButton}}" stepKey="switchCategoryViewToListMode"/> <waitForElement selector="{{StorefrontCategoryMainSection.CategoryTitle}}" time="30" stepKey="waitForCategoryReload"/> </actionGroup> + + <actionGroup name="GoToSubCategoryPage"> + <arguments> + <argument name="parentCategory"/> + <argument name="subCategory"/> + <argument name="urlPath" type="string"/> + </arguments> + <moveMouseOver selector="{{StorefrontHeaderSection.NavigationCategoryByName(parentCategory.name)}}" stepKey="moveMouseOnMainCategory"/> + <waitForElementVisible selector="{{StorefrontHeaderSection.NavigationCategoryByName(subCategory.name)}}" stepKey="waitForSubCategoryVisible"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName(subCategory.name)}}" stepKey="goToCategory"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <seeInCurrentUrl url="{{urlPath}}.html" stepKey="checkUrl"/> + <seeInTitle userInput="{{subCategory.name}}" stepKey="assertCategoryNameInTitle"/> + <see userInput="{{subCategory.name}}" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="assertCategoryName"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/RewriteStoreLevelUrlKeyOfChildCategoryTest.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/RewriteStoreLevelUrlKeyOfChildCategoryTest.xml new file mode 100644 index 0000000000000..67870c51140a6 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/RewriteStoreLevelUrlKeyOfChildCategoryTest.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="RewriteStoreLevelUrlKeyOfChildCategoryTest"> + <annotations> + <title value="Rewriting Store-level URL key of child category"/> + <stories value="MAGETWO-91649: #13513: Magento ignore store-level url_key of child category in URL rewrite process for global scope"/> + <description value="Rewriting Store-level URL key of child category"/> + <features value="CatalogUrlRewrite"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-94934"/> + <group value="CatalogUrlRewrite"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createStoreView" /> + + <createData entity="_defaultCategory" stepKey="defaultCategory"/> + <createData entity="SubCategoryWithParent" stepKey="subCategory"> + <requiredEntity createDataKey="defaultCategory"/> + </createData> + </before> + + <actionGroup ref="navigateToCreatedCategory" stepKey="navigateToCreatedSubCategory"> + <argument name="Category" value="$$subCategory$$"/> + </actionGroup> + + <actionGroup ref="AdminSwitchStoreViewActionGroup" stepKey="AdminSwitchStoreViewForSubCategory"/> + + <actionGroup ref="ChangeSeoUrlKeyForSubCategory" stepKey="changeSeoUrlKeyForSubCategory"> + <argument name="value" value="bags-second"/> + </actionGroup> + + <actionGroup ref="navigateToCreatedCategory" stepKey="navigateToCreatedDefaultCategory"> + <argument name="Category" value="$$defaultCategory$$"/> + </actionGroup> + + <actionGroup ref="ChangeSeoUrlKey" stepKey="changeSeoUrlKeyForDefaultCategory"> + <argument name="value" value="gear-global"/> + </actionGroup> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToStorefrontPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + + <actionGroup ref="StorefrontSwitchStoreViewActionGroup" stepKey="storefrontSwitchStoreView"/> + + <actionGroup ref="GoToSubCategoryPage" stepKey="goToSubCategoryPage"> + <argument name="parentCategory" value="$$defaultCategory$$"/> + <argument name="subCategory" value="$$subCategory$$"/> + <argument name="urlPath" value="gear-global/bags-second"/> + </actionGroup> + + <after> + <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreView"/> + <actionGroup ref="logout" stepKey="logout"/> + + <deleteData createDataKey="subCategory" stepKey="deleteSubCategory"/> + <deleteData createDataKey="defaultCategory" stepKey="deleteNewRootCategory"/> + </after> + </test> +</tests> From f3772212cdc4a7eb34ed7e85e274a0774b6c51de Mon Sep 17 00:00:00 2001 From: Yurii Borysov <yurii_borysov@epam.com> Date: Fri, 28 Sep 2018 14:42:08 +0300 Subject: [PATCH 0116/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Update sorting logic - Add sorting widget --- .../Product/Form/Modifier/GroupedTest.php | 2 + .../Product/Form/Modifier/Grouped.php | 34 ++- .../adminhtml/web/css/grouped-product.css | 37 ++++ .../adminhtml/web/js/grouped-product-grid.js | 209 ++++++++++++++++++ .../web/template/components/position.html | 19 ++ 5 files changed, 295 insertions(+), 6 deletions(-) create mode 100644 app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js create mode 100644 app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html diff --git a/app/code/Magento/GroupedProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GroupedTest.php b/app/code/Magento/GroupedProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GroupedTest.php index 6ef87117deae2..327b47d4a75d8 100644 --- a/app/code/Magento/GroupedProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GroupedTest.php +++ b/app/code/Magento/GroupedProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GroupedTest.php @@ -34,6 +34,7 @@ class GroupedTest extends AbstractModifierTest const LINKED_PRODUCT_NAME = 'linked'; const LINKED_PRODUCT_QTY = '0'; const LINKED_PRODUCT_POSITION = 1; + const LINKED_PRODUCT_POSITION_CALCULATED = 1; const LINKED_PRODUCT_PRICE = '1'; /** @@ -212,6 +213,7 @@ public function testModifyData() 'price' => null, 'qty' => self::LINKED_PRODUCT_QTY, 'position' => self::LINKED_PRODUCT_POSITION, + 'positionCalculated' => self::LINKED_PRODUCT_POSITION_CALCULATED, 'thumbnail' => null, 'type_id' => null, 'status' => null, diff --git a/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php b/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php index 2d1a1d19757e2..57d9bc78aaf28 100644 --- a/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php +++ b/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php @@ -133,7 +133,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function modifyData(array $data) { @@ -143,12 +143,17 @@ public function modifyData(array $data) if ($modelId) { $storeId = $this->locator->getStore()->getId(); $data[$product->getId()]['links'][self::LINK_TYPE] = []; - foreach ($this->productLinkRepository->getList($product) as $linkItem) { + $linkedItems = $this->productLinkRepository->getList($product); + usort($linkedItems, function ($a, $b) { + return $a->getPosition() <=> $b->getPosition(); + }); + foreach ($linkedItems as $index => $linkItem) { if ($linkItem->getLinkType() !== self::LINK_TYPE) { continue; } /** @var \Magento\Catalog\Api\Data\ProductInterface $linkedProduct */ $linkedProduct = $this->productRepository->get($linkItem->getLinkedProductSku(), false, $storeId); + $linkItem->setPosition($index); $data[$modelId]['links'][self::LINK_TYPE][] = $this->fillData($linkedProduct, $linkItem); } $data[$modelId][self::DATA_SOURCE_DEFAULT]['current_store_id'] = $storeId; @@ -175,6 +180,7 @@ protected function fillData(ProductInterface $linkedProduct, ProductLinkInterfac 'price' => $currency->toCurrency(sprintf("%f", $linkedProduct->getPrice())), 'qty' => $linkItem->getExtensionAttributes()->getQty(), 'position' => $linkItem->getPosition(), + 'positionCalculated' => $linkItem->getPosition(), 'thumbnail' => $this->imageHelper->init($linkedProduct, 'product_listing_thumbnail')->getUrl(), 'type_id' => $linkedProduct->getTypeId(), 'status' => $this->status->getOptionText($linkedProduct->getStatus()), @@ -185,7 +191,7 @@ protected function fillData(ProductInterface $linkedProduct, ProductLinkInterfac } /** - * {@inheritdoc} + * @inheritdoc */ public function modifyMeta(array $meta) { @@ -454,7 +460,7 @@ protected function getGrid() 'label' => null, 'renderDefaultRecord' => false, 'template' => 'ui/dynamic-rows/templates/grid', - 'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid', + 'component' => 'Magento_GroupedProduct/js/grouped-product-grid', 'addButton' => false, 'itemTemplate' => 'record', 'dataScope' => 'data.links', @@ -555,6 +561,22 @@ protected function fillMeta() ], ], ], + 'positionCalculated' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'label' => __('Position'), + 'dataType' => Form\Element\DataType\Number::NAME, + 'formElement' => Form\Element\Input::NAME, + 'componentType' => Form\Field::NAME, + 'elementTmpl' => 'Magento_GroupedProduct/components/position', + 'sortOrder' => 90, + 'fit' => true, + 'dataScope' => 'positionCalculated' + ], + ], + ], + ], 'actionDelete' => [ 'arguments' => [ 'data' => [ @@ -563,7 +585,7 @@ protected function fillMeta() 'componentType' => 'actionDelete', 'dataType' => Form\Element\DataType\Text::NAME, 'label' => __('Actions'), - 'sortOrder' => 90, + 'sortOrder' => 100, 'fit' => true, ], ], @@ -577,7 +599,7 @@ protected function fillMeta() 'formElement' => Form\Element\Input::NAME, 'componentType' => Form\Field::NAME, 'dataScope' => 'position', - 'sortOrder' => 100, + 'sortOrder' => 110, 'visible' => false, ], ], diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css b/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css index 3d723387d23b0..1916f222a499b 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css @@ -66,3 +66,40 @@ overflow: hidden; text-overflow: ellipsis; } + + +.position { + width:90px; +} + +.icon-rearrange-position > span { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.icon-forward, +.icon-backward { + -webkit-font-smoothing: antialiased; + font-family: 'Admin Icons'; + font-size: 17px; + speak: none; +} + +.position-widget-input { + text-align: center; + width: 40px; +} + +.icon-forward:before { + content: '\e618'; +} + +.icon-backward:before { + content: '\e619'; +} \ No newline at end of file diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js new file mode 100644 index 0000000000000..0a585eb92958d --- /dev/null +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -0,0 +1,209 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'uiRegistry', + 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid' +], function (_, registry, dynamicRowsGrid) { + 'use strict'; + return dynamicRowsGrid.extend({ + + /** + * Set max element position + * + * @param {Number} position - element position + * @param {Object} elem - instance + */ + setMaxPosition: function (position, elem) { + + if (position || position === 0) { + this.checkMaxPosition(position); + this.sort(position, elem); + if (~~position === this.maxPosition && ~~position > this.getDefaultPageBoundary() + 1) { + this.shiftNextPagesPositions(position); + } + } else { + this.maxPosition += 1; + } + }, + + /** + * Shift positions for next page elements + * + * @param position + */ + shiftNextPagesPositions: function (position) { + console.log("todo: shifting positions to right on next pages related data"); + }, + + + /** + * Update position for element after position from another page is entered + * + * @param data + * @param event + */ + updateGridPosition: function (data, event) { + var inputValue = ~~event.target.value, + recordData = this.recordData(), + record, + updatedRecord; + + record = this.elems().find(function (obj) { + return obj.dataScope === data.parentScope + }).data(); + + if (inputValue === ~~record.positionCalculated) { + return false; + } + + this.elems([]); + + updatedRecord = this.getUpdatedRecordIndex(recordData, record.id); + + if (inputValue >= this.recordData().size() - 1) { + recordData[updatedRecord].position = this.getGlobalMaxPosition() + 1; + } else { + recordData[updatedRecord].position = inputValue; + recordData.forEach(function (value, index) { + if (~~value.id !== ~~record.id) { + recordData[index].position = (index !== inputValue) ? index : index + 1; + } + }); + } + + this.reloadGridData(recordData); + + }, + + /** + * Get updated record index + * + * @param recordData + * @param recordId + * @return {number} + */ + getUpdatedRecordIndex: function (recordData, recordId) { + return recordData.map(function (o) { + return ~~o.id + }).indexOf(~~recordId); + }, + + /** + * + * @param recordData to reprocess + */ + reloadGridData: function (recordData) { + this.recordData(recordData.sort(function (a, b) { + return ~~a.position - ~~b.position; + })); + this._updateCollection(); + this.reload(); + }, + + /** + * Event handler for "Send to bottom" button + * + * @param positionObj + * @return {boolean} + */ + sendToBottom: function (positionObj) { + + var objectToUpdate = this.getObjectToUpdate(positionObj), + recordData = this.recordData(), + updatedRecord; + + if (~~this.currentPage() === this.pages) { + objectToUpdate.position = this.maxPosition; + } else { + this.elems([]); + updatedRecord = this.getUpdatedRecordIndex(recordData, objectToUpdate.data().id); + recordData[updatedRecord].position = this.getGlobalMaxPosition() + 1; + this.reloadGridData(recordData); + } + + return false; + }, + + /** + * Event handler for "Send to top" button + * + * @param positionObj + * @returns {boolean} + */ + sendToTop: function (positionObj) { + var objectToUpdate = this.getObjectToUpdate(positionObj), + recordData = this.recordData(), + updatedRecord; + + //isFirst + if (~~this.currentPage() === 1) { + objectToUpdate.position = 0; + } else { + this.elems([]); + updatedRecord = this.getUpdatedRecordIndex(recordData, objectToUpdate.data().id); + recordData.forEach(function (value, index) { + recordData[index].position = (index === updatedRecord) ? 0 : value.position + 1; + }); + this.reloadGridData(recordData); + } + return false; + }, + + /** + * Get element from grid for update + * + * @param object + * @return {*} + */ + getObjectToUpdate: function (object) { + return this.elems().filter(function (item) { + return item.name === object.parentName; + })[0]; + }, + + /** + * Value function for position input + * + * @param data + * @return {number} + */ + getCalculatedPosition: function (data) { + return (~~this.currentPage() - 1) * this.pageSize + this.elems().pluck("name").indexOf(data.name); + }, + + /** + * Returns start index for current page + * + * @return {number} + */ + getStartIndex() { + return (~~this.currentPage() - 1) * this.pageSize; + }, + + /** + * Return Page Boundary + * + * @return {number} + */ + getDefaultPageBoundary: function () { + return (~~this.currentPage() * this.pageSize) - 1; + }, + + /** + * Returns position for last element to be moved after + * + * @return {number} + */ + getGlobalMaxPosition() { + return _.max(this.recordData().map(function (r) { + return ~~r.position + })); + } + + + }); +}); \ No newline at end of file diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html b/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html new file mode 100644 index 0000000000000..dbfeff2e32c04 --- /dev/null +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html @@ -0,0 +1,19 @@ +<div class="position"> + <a href="#" class="move-top icon-backward icon-rearrange-position" + data-bind=" + click: $parent.sendToTop.bind($parent) + "> + <span>Top</span> + </a> + <input type="text" class="position-widget-input" + data-bind=" + value: $parent.getCalculatedPosition($record()), + event: {blur: $parent.updateGridPosition.bind($parent)} + "/> + <a href="#" class="move-bottom icon-forward icon-rearrange-position" + data-bind=" + click: $parent.sendToBottom.bind($parent) + "> + <span>Bottom</span> + </a> +</div> \ No newline at end of file From c5bf8738d26a07a19a477e14aaf79708ba8052fd Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Fri, 28 Sep 2018 16:59:42 +0400 Subject: [PATCH 0117/1158] MAGETWO-91707: [Sigma Beauty]Cannot pause Youtube video in IE 11 - Add automated test --- .../StorefrontProductInfoMainSection.xml | 4 + .../YoutubeVideoWindowOnProductPageTest.xml | 92 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Test/YoutubeVideoWindowOnProductPageTest.xml diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index 564122f71b9f4..c8e1ebcf12d94 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -10,5 +10,9 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="StorefrontProductInfoMainSection"> <element name="productVideo" type="text" selector="//*[@class='product-video' and @data-type='{{videoType}}']" parameterized="true"/> + <element name="clickInVideo" type="video" selector="//*[@class='fotorama__stage__shaft']"/> + <element name="videoPausedMode" type="video" selector="//*[contains(@class, 'paused-mode')]"/> + <element name="videoPlayedMode" type="video" selector="//*[contains(@class,'playing-mode')]"/> + <element name="frameVideo" type="video" selector="widget2"/> </section> </sections> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/YoutubeVideoWindowOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/YoutubeVideoWindowOnProductPageTest.xml new file mode 100644 index 0000000000000..7249a4223503e --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/YoutubeVideoWindowOnProductPageTest.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="YoutubeVideoWindowOnProductPageTest"> + <annotations> + <features value="ProductVideo"/> + <stories value="MAGETWO-91707: [Sigma Beauty]Cannot pause Youtube video in IE 11"/> + <testCaseId value="MAGETWO-95254"/> + <title value="Youtube video window on the product page"/> + <description value="Check Youtube video window on the product page"/> + <severity value="MAJOR"/> + <group value="ProductVideo"/> + </annotations> + + <before> + <!--Log In--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <!--Create category--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <!--Create product--> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!-- Set product video Youtube api key configuration --> + <createData entity="ProductVideoYoutubeApiKeyConfig" stepKey="setStoreConfig" after="loginAsAdmin"/> + </before> + + <!--Open simple product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductIndex"/> + <waitForPageLoad stepKey="wait1"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGrid"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openFirstProductForEdit"/> + + <!-- Add product video --> + <actionGroup ref="addProductVideo" stepKey="addProductVideo" after="openFirstProductForEdit"/> + <!-- Assert product video in admin product form --> + <actionGroup ref="assertProductVideoAdminProductPage" stepKey="assertProductVideoAdminProductPage" after="addProductVideo"/> + + <!-- Save the product --> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveFirstProduct"/> + <waitForPageLoad stepKey="waitForFirstProductSaved"/> + + <!-- Assert product video in storefront product page --> + <amOnPage url="$$createProduct.name$$.html" stepKey="goToStorefrontCategoryPage"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoaded"/> + <actionGroup ref="assertProductVideoStorefrontProductPage" stepKey="assertProductVideoStorefrontProductPage" after="waitForStorefrontPageLoaded"/> + + <!--Click Play video button--> + <click stepKey="clickToPlayVideo" selector="{{StorefrontProductInfoMainSection.clickInVideo}}"/> + <wait stepKey="waitFiveSecondToPlayVideo" time="5"/> + <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="waitForVideoPlayed"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="AssertVideoIsPlayed"/> + <switchToIFrame stepKey="switchBack1"/> + + <!--Click Pause button--> + <click stepKey="clickToStopVideo" selector="{{StorefrontProductInfoMainSection.clickInVideo}}"/> + <wait stepKey="waitFiveSecondToStopVideo" time="5"/> + <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame2"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPausedMode}}" stepKey="waitForVideoPaused"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPausedMode}}" stepKey="AssertVideoIsPaused"/> + <switchToIFrame stepKey="switchBack2"/> + + <!--Click Play video button again. Make sure that Video continued playing--> + <click stepKey="clickAgainToPlayVideo" selector="{{StorefrontProductInfoMainSection.clickInVideo}}"/> + <wait stepKey="waitAgainFiveSecondToPlayVideo" time="5"/> + <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame3"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="waitForVideoPlayedAgain"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="AssertVideoIsPlayedAgain"/> + <switchToIFrame stepKey="switchBack3"/> + + <after> + <deleteData createDataKey="createProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategoryFirst"/> + <!-- Set product video configuration to default --> + <createData entity="DefaultProductVideoConfig" stepKey="setStoreDefaultConfig" before="logout"/> + <!--Log Out--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + </test> +</tests> + From 8f8fc8d9b868e3e73e2267ccca910efa5fa57378 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Fri, 28 Sep 2018 17:24:18 +0300 Subject: [PATCH 0118/1158] MAGETWO-91751: Apostrophe displays as code in the text field box - Skipping to escape single quote --- app/code/Magento/Widget/Model/Widget.php | 6 +++- .../Widget/Test/Unit/Model/WidgetTest.php | 29 ++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Widget/Model/Widget.php b/app/code/Magento/Widget/Model/Widget.php index 085e6ec3b2d77..5ba03d008ded0 100644 --- a/app/code/Magento/Widget/Model/Widget.php +++ b/app/code/Magento/Widget/Model/Widget.php @@ -84,6 +84,8 @@ public function __construct( } /** + * Get math random + * * @return \Magento\Framework\Math\Random * * @deprecated 100.1.0 @@ -315,7 +317,7 @@ public function getWidgetDeclaration($type, $params = [], $asIs = true) } } if (isset($value)) { - $directive .= sprintf(' %s="%s"', $name, $this->escaper->escapeQuote($value)); + $directive .= sprintf(' %s="%s"', $name, $this->escaper->escapeHtmlAttr($value, false)); } } @@ -339,6 +341,8 @@ public function getWidgetDeclaration($type, $params = [], $asIs = true) } /** + * Get widget page varname + * * @param array $params * @return string * @throws \Magento\Framework\Exception\LocalizedException diff --git a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php index b85a458ed4121..5c546d7e2435c 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php +++ b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php @@ -32,6 +32,9 @@ class WidgetTest extends \PHPUnit\Framework\TestCase */ private $conditionsHelper; + /** + * @inheritdoc + */ protected function setUp() { $this->dataStorageMock = $this->getMockBuilder(\Magento\Widget\Model\Config\Data::class) @@ -55,6 +58,9 @@ protected function setUp() ); } + /** + * Unit test for getWidget + */ public function testGetWidgets() { $expected = ['val1', 'val2']; @@ -65,6 +71,9 @@ public function testGetWidgets() $this->assertEquals($expected, $result); } + /** + * Unit test for getWidgetsWithFilter + */ public function testGetWidgetsWithFilter() { $configFile = __DIR__ . '/_files/mappedConfigArrayAll.php'; @@ -78,6 +87,9 @@ public function testGetWidgetsWithFilter() $this->assertEquals($expected, $result); } + /** + * Unit test for getWidgetsWithUnknownFilter + */ public function testGetWidgetsWithUnknownFilter() { $configFile = __DIR__ . '/_files/mappedConfigArrayAll.php'; @@ -90,6 +102,9 @@ public function testGetWidgetsWithUnknownFilter() $this->assertEquals($expected, $result); } + /** + * Unit test for getWidgetByClassType + */ public function testGetWidgetByClassType() { $widgetOne = ['@' => ['type' => 'type1']]; @@ -101,6 +116,9 @@ public function testGetWidgetByClassType() $this->assertNull($this->widget->getWidgetByClassType('type2')); } + /** + * Unit test for getConfigAsObject + */ public function testGetConfigAsObject() { $configFile = __DIR__ . '/_files/mappedConfigArrayAll.php'; @@ -135,6 +153,9 @@ public function testGetConfigAsObject() $this->assertSame($supportedContainersExpected, $resultObject->getSupportedContainers()); } + /** + * Unit test for getConfigAsObjectWidgetNoFound + */ public function testGetConfigAsObjectWidgetNoFound() { $this->dataStorageMock->expects($this->once()) @@ -146,6 +167,9 @@ public function testGetConfigAsObjectWidgetNoFound() $this->assertSame([], $resultObject->getData()); } + /** + * Unit test for getWidgetDeclaration + */ public function testGetWidgetDeclaration() { $mathRandomMock = $this->createPartialMock(\Magento\Framework\Math\Random::class, ['getRandomString']); @@ -175,7 +199,7 @@ public function testGetWidgetDeclaration() $this->conditionsHelper->expects($this->once())->method('encode')->with($conditions) ->willReturn('encoded-conditions-string'); $this->escaperMock->expects($this->atLeastOnce()) - ->method('escapeQuote') + ->method('escapeHtmlAttr') ->willReturnMap([ ['my "widget"', false, 'my "widget"'], ['1', false, '1'], @@ -203,6 +227,9 @@ public function testGetWidgetDeclaration() $this->assertContains('type_name=""}}', $result); } + /** + * Unit test for getWidgetDeclarationWithZeroValueParam + */ public function testGetWidgetDeclarationWithZeroValueParam() { $mathRandomMock = $this->createPartialMock(\Magento\Framework\Math\Random::class, ['getRandomString']); From a7a43be69cad7ef6ace82ad97756b112ecd6415e Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Mon, 1 Oct 2018 09:56:38 +0300 Subject: [PATCH 0119/1158] MAGETWO-91650: Translation not working for product alerts - Revert changes --- app/code/Magento/ProductAlert/Model/Email.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/ProductAlert/Model/Email.php b/app/code/Magento/ProductAlert/Model/Email.php index 18adc54c2d660..7aee4ca01240d 100644 --- a/app/code/Magento/ProductAlert/Model/Email.php +++ b/app/code/Magento/ProductAlert/Model/Email.php @@ -359,7 +359,6 @@ public function send() $storeId = $this->storeId ?: (int) $this->_customer->getStoreId(); $store = $this->getStore($storeId); - $storeId = $store->getId(); $this->_appEmulation->startEnvironmentEmulation($storeId); @@ -408,6 +407,18 @@ public function send() return true; } + /** + * Retrieve the store for the email + * + * @param int $storeId + * @return StoreInterface + * @throws NoSuchEntityException + */ + private function getStore(int $storeId): StoreInterface + { + return $this->_storeManager->getStore($storeId); + } + /** * Retrieve the block for the email based on type * From cc00197d13d6244e32201e4c6bf00287e54747c5 Mon Sep 17 00:00:00 2001 From: Stsiapan Korf <Stsiapan_Korf@epam.com> Date: Mon, 1 Oct 2018 13:49:26 +0300 Subject: [PATCH 0120/1158] MAGETWO-91702: Shipping method Table Rates settings gets from wrong store - Fix website id for shipping --- app/code/Magento/Quote/Model/Quote/Address.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 11beffe5711b9..140ace42afae1 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -1003,8 +1003,14 @@ public function requestShippingRates(\Magento\Quote\Model\Quote\Item\AbstractIte /** * Store and website identifiers specified from StoreManager */ - $request->setStoreId($this->getQuote()->getStoreId() ?? $this->storeManager->getStore()->getId()); - $request->setWebsiteId($this->storeManager->getWebsite()->getId()); + if ($this->getQuote()->getStoreId()) { + $storeId = $this->getQuote()->getStoreId(); + $request->setStoreId($storeId); + $request->setWebsiteId($this->storeManager->getStore($storeId)->getWebsiteId()); + } else { + $request->setStoreId($this->storeManager->getStore()->getId()); + $request->setWebsiteId($this->storeManager->getWebsite()->getId()); + } $request->setFreeShipping($this->getFreeShipping()); /** * Currencies need to convert in free shipping From d9ee86dc4d2e7072dd768375ce393f4771c175e6 Mon Sep 17 00:00:00 2001 From: Oleg Onufer <linkedddd@gmail.com> Date: Mon, 1 Oct 2018 14:40:49 +0300 Subject: [PATCH 0121/1158] MAGETWO-95307: Url-rewrites for product in anchor categories --- .../Mftf/Page/AdminUrlRewriteIndexPage.xml | 14 ++++ .../Section/AdminUrlRewriteIndexSection.xml | 16 ++++ ...writesForProductInAnchorCategoriesTest.xml | 81 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 app/code/Magento/UrlRewrite/Test/Mftf/Page/AdminUrlRewriteIndexPage.xml create mode 100644 app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml create mode 100644 app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Page/AdminUrlRewriteIndexPage.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Page/AdminUrlRewriteIndexPage.xml new file mode 100644 index 0000000000000..c7c450a00a0c3 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Page/AdminUrlRewriteIndexPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminUrlRewriteIndexPage" url="admin/url_rewrite/index/" area="admin" module="Magento_UrlRewrite"> + <section name="AdminUrlRewriteIndexSection"/> + </page> +</pages> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml new file mode 100644 index 0000000000000..a7a17482a8ec1 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminUrlRewriteIndexSection"> + <element name="requestPathSearchField" type="input" selector="#urlrewriteGrid_filter_request_path"/> + <element name="requestPathColumns" type="text" selector="//td[@data-column='request_path'][not(input)]"/> + <element name="search" type="button" selector="[data-action='grid-filter-apply']" timeout="10"/> + </section> +</sections> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml new file mode 100644 index 0000000000000..8591b0f93f926 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminUrlRewritesForProductInAnchorCategoriesTest"> + <annotations> + <features value="Url Rewrite"/> + <stories value="Url-rewrites for product in anchor categories"/> + <title value="Url-rewrites for product in anchor categories"/> + <description value="For a product with category that has parent anchor categories, the rewrites is created when the category/product is saved."/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-69826"/> + <group value="UrlRewrite"/> + </annotations> + + <!-- Preconditions--> + <!-- Create 3 categories --> + <before> + <createData entity="SimpleSubCategory" stepKey="simpleSubCategory1"/> + <createData entity="SubCategoryWithParent" stepKey="simpleSubCategory2"> + <requiredEntity createDataKey="simpleSubCategory1"/> + </createData> + <createData entity="SubCategoryWithParent" stepKey="simpleSubCategory3"> + <requiredEntity createDataKey="simpleSubCategory2"/> + </createData> + <!-- Create Simple product 1 and assign it to Category 3 --> + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="simpleSubCategory3"/> + </createData> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="simpleSubCategory3" stepKey="deletesimpleSubCategory3"/> + <deleteData createDataKey="simpleSubCategory2" stepKey="deletesimpleSubCategory2"/> + <deleteData createDataKey="simpleSubCategory1" stepKey="deletesimpleSubCategory1"/> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + </after> + <!-- Steps --> + <!-- 1. Log in to Admin --> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- 2. Open Marketing - SEO & Search - URL Rewrites --> + <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="amOnUrlRewriteIndexPage"/> + <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName"/> + <click selector="{{AdminUrlRewriteIndexSection.search}}" stepKey="clickSearchButton"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue1"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue2"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue3"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue4"/> + + <!-- 3. Edit Category 1 for DEFAULT Store View: --> + <actionGroup ref="switchCategoryStoreView" stepKey="SwitchStoreView"> + <argument name="Store" value="_defaultStore.name"/> + <argument name="CatName" value="SimpleSubCategory.name"/> + </actionGroup> + <click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="openSeoSection2"/> + <uncheckOption selector="{{AdminCategorySEOSection.UrlKeyDefaultValueCheckbox}}" stepKey="uncheckRedirect2"/> + <fillField selector="{{AdminCategorySEOSection.UrlKeyInput}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new" stepKey="changeURLKey"/> + + <!-- 4. Save Category 1 --> + <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategory"/> + <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="assertSuccessMessageAfterSaved"/> + + <!-- 5. Open Marketing - SEO & Search - URL Rewrites --> + <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="amOnUrlRewriteIndexPage2"/> + <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName2"/> + <click selector="{{AdminUrlRewriteIndexSection.search}}" stepKey="clickSearchButton2"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue1"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.name$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue2"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.name$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue3"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.name$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue4"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue5"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue6"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue7"/> + </test> +</tests> From 94d735e033314f6c384f0eba51647d9219f62ed8 Mon Sep 17 00:00:00 2001 From: Oleg Onufer <linkedddd@gmail.com> Date: Mon, 1 Oct 2018 17:06:00 +0300 Subject: [PATCH 0122/1158] MAGETWO-95307: Url-rewrites for product in anchor categories --- .../AdminUrlRewritesForProductInAnchorCategoriesTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml index 8591b0f93f926..22c27042aad52 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml @@ -71,9 +71,9 @@ <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName2"/> <click selector="{{AdminUrlRewriteIndexSection.search}}" stepKey="clickSearchButton2"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue1"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.name$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue2"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.name$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue3"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.name$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue4"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue2"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue3"/> + <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue4"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue5"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue6"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue7"/> From 149242f9d23d1a8d352d5c5c532ba0b1be3e5bd9 Mon Sep 17 00:00:00 2001 From: Yurii Borysov <yurii_borysov@epam.com> Date: Mon, 1 Oct 2018 17:33:14 +0300 Subject: [PATCH 0123/1158] MAGETWO-91530: Expose Authorize.net Response Codes in Checkout - Propagate payment error message --- .../Payment/view/frontend/templates/transparent/iframe.phtml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml index c127371cb5f47..35dbfe9622bea 100644 --- a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml +++ b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml @@ -40,9 +40,7 @@ $params = $block->getParams(); $(parent).trigger('clearTimeout'); fullScreenLoader.stopLoader(); globalMessageList.addErrorMessage({ - message: $t( - 'A server error stopped your order from being placed. Please try to place your order again.' - ) + message: $t(<?=json_encode($params['error_msg'])?>) }); } ); From 772ae6b8df140d0b88f804c5ddf18266fdc18f13 Mon Sep 17 00:00:00 2001 From: Oleg Onufer <linkedddd@gmail.com> Date: Mon, 1 Oct 2018 17:34:22 +0300 Subject: [PATCH 0124/1158] MAGETWO-95307: Url-rewrites for product in anchor categories --- .../Test/Mftf/Section/AdminUrlRewriteIndexSection.xml | 1 - .../AdminUrlRewritesForProductInAnchorCategoriesTest.xml | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml index a7a17482a8ec1..3c445b5cf3e6f 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml @@ -11,6 +11,5 @@ <section name="AdminUrlRewriteIndexSection"> <element name="requestPathSearchField" type="input" selector="#urlrewriteGrid_filter_request_path"/> <element name="requestPathColumns" type="text" selector="//td[@data-column='request_path'][not(input)]"/> - <element name="search" type="button" selector="[data-action='grid-filter-apply']" timeout="10"/> </section> </sections> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml index 22c27042aad52..562d414a63ddb 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml @@ -15,7 +15,7 @@ <description value="For a product with category that has parent anchor categories, the rewrites is created when the category/product is saved."/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-69826"/> - <group value="UrlRewrite"/> + <group value="urlRewrite"/> </annotations> <!-- Preconditions--> @@ -47,7 +47,7 @@ <!-- 2. Open Marketing - SEO & Search - URL Rewrites --> <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="amOnUrlRewriteIndexPage"/> <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName"/> - <click selector="{{AdminUrlRewriteIndexSection.search}}" stepKey="clickSearchButton"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickSearchButton"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue1"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue2"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue3"/> @@ -69,7 +69,7 @@ <!-- 5. Open Marketing - SEO & Search - URL Rewrites --> <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="amOnUrlRewriteIndexPage2"/> <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName2"/> - <click selector="{{AdminUrlRewriteIndexSection.search}}" stepKey="clickSearchButton2"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickSearchButton2"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue1"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue2"/> <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue3"/> From 720a5c63e11d75615e2f3de6c452f5aa097ba0fe Mon Sep 17 00:00:00 2001 From: Yurii Borysov <yurii_borysov@epam.com> Date: Mon, 1 Oct 2018 17:51:19 +0300 Subject: [PATCH 0125/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix CR Issues --- .../GroupedProduct/view/adminhtml/web/css/grouped-product.css | 2 +- .../view/adminhtml/web/js/grouped-product-grid.js | 2 +- .../view/adminhtml/web/template/components/position.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css b/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css index 1916f222a499b..cd0aa25ae1f88 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css @@ -102,4 +102,4 @@ .icon-backward:before { content: '\e619'; -} \ No newline at end of file +} diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 0a585eb92958d..7c9563bb1a0ce 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -206,4 +206,4 @@ define([ }); -}); \ No newline at end of file +}); diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html b/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html index dbfeff2e32c04..050fb3c2898ce 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/template/components/position.html @@ -16,4 +16,4 @@ "> <span>Bottom</span> </a> -</div> \ No newline at end of file +</div> From b77c7acf6ee5dca25ab9431e83de91bb00b58795 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Mon, 1 Oct 2018 17:59:51 +0300 Subject: [PATCH 0126/1158] MAGETWO-58210: Import Products sets default behaviour as append, need add_update - Added "add_update" behavior for checking by default --- .../ImportExport/Model/Import/Entity/AbstractEntity.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php index e965e8ad207fd..96704667bfc61 100644 --- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php +++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php @@ -554,6 +554,7 @@ public function getBehavior() $this->_parameters['behavior'] ) || $this->_parameters['behavior'] != ImportExport::BEHAVIOR_APPEND && + $this->_parameters['behavior'] != ImportExport::BEHAVIOR_ADD_UPDATE && $this->_parameters['behavior'] != ImportExport::BEHAVIOR_REPLACE && $this->_parameters['behavior'] != ImportExport::BEHAVIOR_DELETE ) { @@ -828,6 +829,8 @@ public function validateData() } /** + * Get instance of error aggregator. + * * @return ProcessingErrorAggregatorInterface */ public function getErrorAggregator() From 440e9eb40884e12236f820f9ba1e52cb704e702f Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Tue, 2 Oct 2018 09:47:30 +0300 Subject: [PATCH 0127/1158] MAGETWO-91711: Unable to delete downloadable product links if sample links are not deleted - Set empty arrays if info doesn't come from request. --- .../Product/Initialization/Helper/Plugin/Downloadable.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/Downloadable/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Downloadable.php b/app/code/Magento/Downloadable/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Downloadable.php index f56b219f72db2..a283891afc406 100644 --- a/app/code/Magento/Downloadable/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Downloadable.php +++ b/app/code/Magento/Downloadable/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Downloadable.php @@ -11,6 +11,9 @@ use Magento\Downloadable\Api\Data\SampleInterfaceFactory; use Magento\Downloadable\Api\Data\LinkInterfaceFactory; +/** + * Class for initialization downloadable info from request. + */ class Downloadable { /** @@ -92,6 +95,8 @@ public function afterInitialize( } } $extension->setDownloadableProductLinks($links); + } else { + $extension->setDownloadableProductLinks([]); } if (isset($downloadable['sample']) && is_array($downloadable['sample'])) { $samples = []; @@ -107,6 +112,8 @@ public function afterInitialize( } } $extension->setDownloadableProductSamples($samples); + } else { + $extension->setDownloadableProductSamples([]); } $product->setExtensionAttributes($extension); if ($product->getLinksPurchasedSeparately()) { From 45eecf58054aa9c22cdae6fb7f397371d79ddf75 Mon Sep 17 00:00:00 2001 From: Oleg Onufer <linkedddd@gmail.com> Date: Tue, 2 Oct 2018 11:46:32 +0300 Subject: [PATCH 0128/1158] MAGETWO-95307: Url-rewrites for product in anchor categories --- .../Section/AdminUrlRewriteIndexSection.xml | 4 +-- ...writesForProductInAnchorCategoriesTest.xml | 34 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml index 3c445b5cf3e6f..0880b50950e15 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml @@ -9,7 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminUrlRewriteIndexSection"> - <element name="requestPathSearchField" type="input" selector="#urlrewriteGrid_filter_request_path"/> - <element name="requestPathColumns" type="text" selector="//td[@data-column='request_path'][not(input)]"/> + <element name="requestPathFilter" type="input" selector="#urlrewriteGrid_filter_request_path"/> + <element name="requestPathColumnValue" type="text" selector="//*[@id='urlrewriteGrid']//tbody//td[@data-column='request_path' and normalize-space(.)='{{columnValue}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml index 562d414a63ddb..0d9df9176d2b5 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest.xml @@ -35,8 +35,6 @@ </before> <after> <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> - <deleteData createDataKey="simpleSubCategory3" stepKey="deletesimpleSubCategory3"/> - <deleteData createDataKey="simpleSubCategory2" stepKey="deletesimpleSubCategory2"/> <deleteData createDataKey="simpleSubCategory1" stepKey="deletesimpleSubCategory1"/> <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> </after> @@ -46,36 +44,36 @@ <!-- 2. Open Marketing - SEO & Search - URL Rewrites --> <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="amOnUrlRewriteIndexPage"/> - <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName"/> + <fillField selector="{{AdminUrlRewriteIndexSection.requestPathFilter}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName"/> <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickSearchButton"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue1"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue2"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue3"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeValue4"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeValue1"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeValue2"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeValue3"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeValue4"/> <!-- 3. Edit Category 1 for DEFAULT Store View: --> - <actionGroup ref="switchCategoryStoreView" stepKey="SwitchStoreView"> + <actionGroup ref="switchCategoryStoreView" stepKey="switchStoreView"> <argument name="Store" value="_defaultStore.name"/> - <argument name="CatName" value="SimpleSubCategory.name"/> + <argument name="CatName" value="$$simpleSubCategory1.name$$"/> </actionGroup> <click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="openSeoSection2"/> <uncheckOption selector="{{AdminCategorySEOSection.UrlKeyDefaultValueCheckbox}}" stepKey="uncheckRedirect2"/> <fillField selector="{{AdminCategorySEOSection.UrlKeyInput}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new" stepKey="changeURLKey"/> - + <checkOption selector="{{AdminCategorySEOSection.UrlKeyRedirectCheckbox}}" stepKey="checkUrlKeyRedirect"/> <!-- 4. Save Category 1 --> <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategory"/> <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="assertSuccessMessageAfterSaved"/> <!-- 5. Open Marketing - SEO & Search - URL Rewrites --> <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="amOnUrlRewriteIndexPage2"/> - <fillField selector="{{AdminUrlRewriteIndexSection.requestPathSearchField}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName2"/> + <fillField selector="{{AdminUrlRewriteIndexSection.requestPathFilter}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="inputProductName2"/> <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickSearchButton2"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue1"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue2"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue3"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue4"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue5"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue6"/> - <see selector="{{AdminUrlRewriteIndexSection.requestPathColumns}}" userInput="$simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html" stepKey="seeInListValue7"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue1"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue2"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue3"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue4"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$-new/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue5"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue6"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.requestPathColumnValue($simpleSubCategory1.custom_attributes[url_key]$-new/$simpleSubCategory2.custom_attributes[url_key]$/$simpleSubCategory3.custom_attributes[url_key]$/$createSimpleProduct.custom_attributes[url_key]$.html)}}" stepKey="seeInListValue7"/> </test> </tests> From 02094f2ef0891f14d2b5e6a5e024379817dd3f7e Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Fri, 28 Sep 2018 11:33:24 +0400 Subject: [PATCH 0129/1158] MAGETWO-91639: Tax is added despite customer group changes - Add automated test --- ...AdminConfigCreateNewAccountActionGroup.xml | 25 +++ .../AdminStoresCustomerConfigurationPage.xml | 12 ++ ...dminStoresCustomerConfigurationSection.xml | 14 ++ .../AdminCreateCustomerGroupActionGroup.xml | 25 +++ .../AdminDeleteCustomerGroupActionGroup.xml | 31 ++++ ...SignUpNewUserFromStorefrontActionGroup.xml | 5 + .../Customer/Test/Mftf/Data/AddressData.xml | 7 + .../Mftf/Data/CustomerConfigurationData.xml | 40 +++++ .../customer_create_new_account-meta.xml | 28 ++++ .../Test/Mftf/Page/AdminCustomerGroupPage.xml | 14 ++ .../Mftf/Page/AdminNewCustomerGroupPage.xml | 14 ++ .../Section/AdminCustomerGroupMainSection.xml | 19 +++ .../Section/AdminNewCustomerGroupSection.xml | 18 +++ ...StorefrontCheckTaxAddingValidVATIdTest.xml | 147 ++++++++++++++++++ .../AdminCustomerTaxClassActionGroup.xml | 42 +++++ .../Tax/Test/Mftf/Data/TaxCodeData.xml | 12 ++ .../Tax/Test/Mftf/Data/TaxRuleData.xml | 6 + .../Mftf/Section/AdminTaxRulesSection.xml | 4 + 18 files changed, 463 insertions(+) create mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml create mode 100644 app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml create mode 100644 app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml create mode 100644 app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml new file mode 100644 index 0000000000000..084f4ce92f0f8 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="SetGroupForValidVATIdIntraUnionActionGroup"> + <arguments> + <argument name="value" type="string"/> + </arguments> + <amOnPage url="{{AdminStoresCustomerConfigurationPage.url}}" stepKey="navigateToCustomerConfigurationPage" /> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick stepKey="expandCreateNewAccountOptionsTab" selector="{{AdminStoresCustomerConfigurationSection.createNewAccOpt}}" dependentSelector="{{AdminStoresCustomerConfigurationSection.enableAutoAssignCustomerGroup}}" visible="false"/> + <waitForElementVisible selector="{{AdminStoresCustomerConfigurationSection.createNewAccOpt}}" stepKey="waitForElementsAppeared"/> + <selectOption selector="{{AdminStoresCustomerConfigurationSection.groupForValidVATIdIntraUnion}}" userInput="{{value}}" stepKey="selectValue"/> + <click selector="{{AdminStoresCustomerConfigurationSection.createNewAccOpt}}" stepKey="collapseTab" /> + <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig"/> + <waitForPageLoad stepKey="waitForConfigSaved"/> + <see userInput="You saved the configuration." stepKey="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml b/app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml new file mode 100644 index 0000000000000..6a4efb6b9e152 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminStoresCustomerConfigurationPage" url="admin/system_config/edit/section/customer/" area="admin" module="Magento_Config"> + <section name="AdminStoresCustomerConfigurationSection"/> + </page> +</pages> diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml new file mode 100644 index 0000000000000..823be383ce123 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminStoresCustomerConfigurationSection"> + <element name="createNewAccOpt" type="button" selector="#customer_create_account-head"/> + <element name="enableAutoAssignCustomerGroup" type="button" selector="#customer_create_account_auto_group_assign"/> + <element name="groupForValidVATIdIntraUnion" type="select" selector="#customer_create_account_viv_intra_union_group"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml new file mode 100644 index 0000000000000..ba984a4d82562 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateCustomerGroupActionGroup"> + <arguments> + <argument name="groupName" type="string"/> + <argument name="taxClass" type="string"/> + </arguments> + <amOnPage url="{{AdminNewCustomerGroupPage.url}}" stepKey="goToNewCustomerGroupPage"/> + <waitForPageLoad stepKey="waitForNewCustomerGroupPageLoad"/> + + <!--Set tax class for customer group--> + <fillField stepKey="fillGroupName" selector="{{AdminNewCustomerGroupSection.groupName}}" userInput="{{groupName}}"/> + <selectOption selector="{{AdminNewCustomerGroupSection.taxClass}}" userInput="{{taxClass}}" stepKey="selectTaxClassOption"/> + <click selector="{{AdminNewCustomerGroupSection.saveCustomerGroup}}" stepKey="clickToSaveCustomerGroup"/> + <waitForPageLoad stepKey="waitForCustomerGroupSaved"/> + <see stepKey="seeCustomerGroupSaveMessage" userInput="You saved the customer group."/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml new file mode 100644 index 0000000000000..9d5b0ea56cd75 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCustomerGroupActionGroup"> + <arguments> + <argument name="groupName" type="string"/> + </arguments> + <amOnPage url="{{AdminCustomerGroupPage.url}}" stepKey="navigateToCustomersGroupPage"/> + <waitForPageLoad stepKey="waitForPageOpened"/> + <click stepKey="clickFiltersBtn" selector="{{AdminCustomerGroupMainSection.filterBtn}}"/> + <fillField selector="{{AdminCustomerGroupMainSection.groupField}}" userInput="{{groupName}}" stepKey="fillFieldGroupName"/> + <click stepKey="clickApplyBtn" selector="{{AdminCustomerGroupMainSection.applyFiltersBtn}}"/> + <!--Here we need to use Implicit wait.--> + <wait stepKey="waitForFilteringFinished" time="2"/> + <click stepKey="clickSelectBtn" selector="{{AdminCustomerGroupMainSection.selectFirstRow}}"/> + <wait stepKey="waitForDropDownOpened" time="2"/> + <click stepKey="clickDeleteBtn" selector="{{AdminCustomerGroupMainSection.deleteBtn}}"/> + <waitForPageLoad stepKey="waitForConfirmationAlert"/> + <click stepKey="accept" selector="{{AdminCustomerGridMainActionsSection.ok}}"/> + <see stepKey="seeSuccessMessage" userInput="You deleted the customer group."/> + <wait stepKey="waitForClearAllBtnVisible" time="2"/> + <click stepKey="clearAllBtn" selector="{{AdminCustomerGroupMainSection.clearAllBtn}}"/> + <waitForElementNotVisible selector="{{AdminCustomerGroupMainSection.clearAllBtn}}" stepKey="waitForElementNotVisible"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml index 79cc00d4474b1..227085fce9de4 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml @@ -46,4 +46,9 @@ <click stepKey="saveAddress" selector="{{StorefrontCustomerAddressSection.saveAddress}}"/> </actionGroup> + + <actionGroup name="SignUpNewCustomerStorefrontActionGroup" extends="SignUpNewUserFromStorefrontActionGroup"> + <waitForPageLoad stepKey="waitForRegistered" after="clickCreateAccountButton"/> + <remove keyForRemoval="seeThankYouMessage" after="waitForRegistered"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index d090620145105..2cdddd48ed0e7 100755 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -106,4 +106,11 @@ <data key="country_id">GB</data> <data key="telephone">444-44-444-44</data> </entity> + <entity name="UK_Simple_Address" extends="UK_Not_Default_Address"> + <array key="street"> + <item>172, Westminster Bridge Rd</item> + <item>7700 xyz street</item> + </array> + <data key="state">California</data> + </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml new file mode 100644 index 0000000000000..60d8b13887ec9 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SetCustomerCreateNewAccountOptionsConfig" type="customer_create_new_account_config"> + <requiredEntity type="auto_group_assign">EnableAutomaticAssignmentCustomerGroup</requiredEntity> + <requiredEntity type="viv_on_each_transaction">EnableValidateEachTransaction</requiredEntity> + <requiredEntity type="vat_frontend_visibility">EnableShowVATNumberStorefront</requiredEntity> + </entity> + <entity name="EnableAutomaticAssignmentCustomerGroup" type="auto_group_assign"> + <data key="value">1</data> + </entity> + <entity name="EnableValidateEachTransaction" type="viv_on_each_transaction"> + <data key="value">1</data> + </entity> + <entity name="EnableShowVATNumberStorefront" type="vat_frontend_visibility"> + <data key="value">1</data> + </entity> + + <entity name="SetCustomerCreateNewAccountOptionsDefaultConfig" type="customer_create_new_account_config"> + <requiredEntity type="auto_group_assign">DefaultAutomaticAssignmentCustomerGroup</requiredEntity> + <requiredEntity type="viv_on_each_transaction">DefaultValidateEachTransaction</requiredEntity> + <requiredEntity type="vat_frontend_visibility">DefaultShowVATNumberStorefront</requiredEntity> + </entity> + <entity name="DefaultAutomaticAssignmentCustomerGroup" type="auto_group_assign"> + <data key="value">0</data> + </entity> + <entity name="DefaultValidateEachTransaction" type="viv_on_each_transaction"> + <data key="value">0</data> + </entity> + <entity name="DefaultShowVATNumberStorefront" type="vat_frontend_visibility"> + <data key="value">0</data> + </entity> +</entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml b/app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml new file mode 100644 index 0000000000000..89ed477cb32d1 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CustomerCreateNewAccountOptionsConfigState" dataType="customer_create_new_account_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/customer/" method="POST"> + <object key="groups" dataType="customer_create_new_account_config"> + <object key="create_account" dataType="customer_create_new_account_config"> + <object key="fields" dataType="customer_create_new_account_config"> + <object key="auto_group_assign" dataType="auto_group_assign"> + <field key="value">string</field> + </object> + <object key="viv_on_each_transaction" dataType="viv_on_each_transaction"> + <field key="value">string</field> + </object> + <object key="vat_frontend_visibility" dataType="vat_frontend_visibility"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml new file mode 100644 index 0000000000000..9adda6a74ba99 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminCustomerGroupPage" url="/customer/group/" area="admin" module="Magento_Customer"> + <section name="AdminCustomerGroupMainSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml new file mode 100644 index 0000000000000..2c52b3ec05c2e --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminNewCustomerGroupPage" url="/customer/group/new/" area="admin" module="Magento_Customer"> + <section name="AdminNewCustomerGroupSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml new file mode 100644 index 0000000000000..1fdb15f189ace --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupMainSection"> + <element name="filterBtn" type="button" selector="//button[text()='Filters']"/> + <element name="groupField" type="input" selector="//*[@name='customer_group_code']"/> + <element name="applyFiltersBtn" type="button" selector="//*[text()='Apply Filters']"/> + <element name="selectFirstRow" type="button" selector="//button[@class='action-select']"/> + <element name="deleteBtn" type="button" selector="//*[text()='Delete']"/> + <element name="clearAllBtn" type="button" selector="//button[text()='Clear all']"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml new file mode 100644 index 0000000000000..ec4a64b01467b --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminNewCustomerGroupSection"> + <element name="groupName" type="input" selector="#customer_group_code"/> + <element name="taxClass" type="select" selector="#tax_class_id"/> + <element name="saveCustomerGroup" type="button" selector="#save"/> + <element name="resetBtn" type="button" selector="#reset"/> + <element name="backBtn" type="button" selector="#back"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml new file mode 100644 index 0000000000000..d38aa9dfdd6c9 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCheckTaxAddingValidVATIdTest"> + <annotations> + <features value="Customer"/> + <stories value="MAGETWO-91639: Tax is added despite customer group changes"/> + <title value="Check tax adding when it's changed to 'Valid VAT ID - Intra-Union'"/> + <description value="Tax should be applied"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95028"/> + <group value="customer"/> + </annotations> + <before> + <!--Log In--> + <actionGroup ref="LoginAsAdmin" stepKey="logIn"/> + <!--Create category--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <!--Create product--> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + + <!--Add new tax rates. Go to tax rule page --> + <actionGroup ref="addNewTaxRuleActionGroup" stepKey="addFirstTaxRuleActionGroup"/> + <fillField stepKey="fillRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="{{TaxRule.name}}"/> + + <!-- Add NY and CA tax rules --> + <actionGroup ref="addNewTaxRateNoZip" stepKey="addSimpleTaxUK"> + <argument name="taxCode" value="SimpleTaxUK"/> + </actionGroup> + <click stepKey="clickSave" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + <waitForPageLoad stepKey="waitForNewTaxRuleCreated"/> + + <!-- Go to tax rule page to create second Tax Rule--> + <actionGroup ref="addNewTaxRuleActionGroup" stepKey="addSecondTaxRuleActionGroup"/> + <fillField stepKey="fillSecondRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="{{TaxRuleZeroRate.name}}"/> + <actionGroup ref="addNewTaxRateNoZip" stepKey="addSimpleTaxUKZeroRate"> + <argument name="taxCode" value="SimpleTaxUKZeroRate"/> + </actionGroup> + <actionGroup ref="addCustomerTaxClass" stepKey="addCustomerTaxClass"> + <argument name="customerTaxClassName" value="UK_zero"/> + </actionGroup> + <click stepKey="disableDefaultProdTaxClass" selector="{{AdminTaxRulesSection.defaultCustomerTaxClass}}"/> + <click stepKey="clickSaveBtn" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + <waitForPageLoad stepKey="waitForSecondTaxRuleCreated"/> + + <!--Create a Customer Group (CUSTOMERS > Customer Groups)--> + <actionGroup ref="AdminCreateCustomerGroupActionGroup" stepKey="createCustomerGroup"> + <argument name="groupName" value="test_UK"/> + <argument name="taxClass" value="UK_zero"/> + </actionGroup> + + <!--Set Customer Create New Account Options Config--> + <createData entity="SetCustomerCreateNewAccountOptionsConfig" stepKey="setCustomerCreateNewAccountOptionsConfig"/> + <actionGroup ref="SetGroupForValidVATIdIntraUnionActionGroup" stepKey="setGroupForValidVATIdIntraUnionActionGroup" after="setCustomerCreateNewAccountOptionsConfig"> + <argument name="value" value="test_UK"/> + </actionGroup> + + <!--Register customer on storefront--> + <actionGroup ref="SignUpNewCustomerStorefrontActionGroup" stepKey="createAnAccount"> + <argument name="Customer" value="CustomerEntityOne"/> + </actionGroup> + + <!--Go to My account > Address book--> + <actionGroup ref="EnterCustomerAddressInfo" stepKey="enterAddressInfo"> + <argument name="Address" value="UK_Simple_Address"/> + </actionGroup> + + <!-- Go to product visible --> + <amOnPage url="$$createProduct.name$$.html" stepKey="navigateToProductPageOnDefaultStore"/> + <see userInput="$$createProduct.name$$" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="assertFirstProductNameTitle"/> + + <!--Add a product to the cart--> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForAddProductToCart"/> + <!--Proceed to checkout--> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="GoToCheckoutFromMinicartActionGroup"/> + <!-- Click next button to open payment section --> + <click selector="{{CheckoutShippingGuestInfoSection.next}}" stepKey="clickNext"/> + <waitForPageLoad stepKey="waitForShipmentPageLoad"/> + + <!-- Check order summary in checkout --> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <!--Verify that Tax 50% is applied --> + <see userInput="$123.00" selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" stepKey="assertSubtotal"/> + <see userInput="$5.00" selector="{{CheckoutPaymentSection.orderSummaryShippingTotal}}" stepKey="assertShipping"/> + <see userInput="Flat Rate - Fixed" selector="{{CheckoutPaymentSection.orderSummaryShippingMethod}}" stepKey="assertShippingMethod"/> + <see userInput="$61.50" selector="{{CheckoutPaymentSection.tax}}" stepKey="assertTax"/> + <see userInput="$189.50" selector="{{CheckoutPaymentSection.orderSummaryTotal}}" stepKey="assertTotal"/> + + <after> + <!-- Go to the tax rule page and delete the row we created--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> + <waitForPageLoad stepKey="waitForRulesPage"/> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteRule"> + <argument name="name" value="{{TaxRule.name}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteSecondRule"> + <argument name="name" value="{{TaxRuleZeroRate.name}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <!-- Go to the tax rate page --> + <amOnPage url="{{AdminTaxRateGridPage.url}}" stepKey="goToTaxRatesPage"/> + <waitForPageLoad stepKey="waitForRatesPage"/> + + <!-- Delete the two tax rates that were created --> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteNYRate"> + <argument name="name" value="{{SimpleTaxUK.state}}-{{SimpleTaxUK.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteCARate"> + <argument name="name" value="{{SimpleTaxUKZeroRate.state}}-{{SimpleTaxUKZeroRate.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <!--Delete created customer group--> + <actionGroup ref="AdminDeleteCustomerGroupActionGroup" stepKey="deleteCustomerGroup"> + <argument name="groupName" value="test_UK"/> + </actionGroup> + + <createData entity="SetCustomerCreateNewAccountOptionsDefaultConfig" stepKey="setCustomerCreateNewAccountOptionsDefaultConfig"/> + <deleteData createDataKey="createProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategoryFirst"/> + + <actionGroup ref="deleteProductTaxClass" stepKey="deleteFirstProductTaxClass"> + <argument name="taxClassName" value="UK_zero"/> + </actionGroup> + + <!--Log Out--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + </test> +</tests> diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml new file mode 100644 index 0000000000000..04d497b4b5246 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!--Add Customer Tax Class--> + <actionGroup name="addCustomerTaxClass"> + <arguments> + <argument name="customerTaxClassName" type="string"/> + </arguments> + <!--Click Additional Settings--> + <click stepKey="clickAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <!--Click Product Add New Tax Class Button--> + <click stepKey="clickCustomerAddNewTaxClassBtn" selector="{{AdminTaxRulesSection.customerAddNewTaxClass}}"/> + <!--Fill field--> + <fillField stepKey="fillCustomerNewTaxClass" selector="{{AdminTaxRulesSection.fieldCustomerNewTaxClass}}" userInput="{{customerTaxClassName}}"/> + <!-- Save Product tax rate --> + <click stepKey="saveProdTaxRate" selector="{{AdminTaxRulesSection.saveCustomerNewTaxClass}}"/> + </actionGroup> + + <!--Delete Product Tax Class--> + <actionGroup name="deleteCustomerTaxClass"> + <arguments> + <argument name="taxClassName" type="string"/> + </arguments> + <!-- Go to tax rule page --> + <amOnPage url="{{AdminNewTaxRulePage.url}}" stepKey="goToNewTaxRulePage"/> + <waitForPageLoad stepKey="waitForTaxRatePage"/> + <click stepKey="clickAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <scrollTo stepKey="scrollToAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <moveMouseOver stepKey="hoverDeleteElement" selector="{{AdminTaxRulesSection.deleteTaxClassName(taxClassName)}}"/> + <click stepKey="deleteFirstTaxClass" selector="{{AdminTaxRulesSection.deleteTaxClass(taxClassName)}}"/> + <waitForElementVisible selector="{{AdminTaxRulesSection.popUpDialogOK}}" stepKey="waitForElementBecomeVisible"/> + <click stepKey="acceptPopUpDialog" selector="{{AdminTaxRulesSection.popUpDialogOK}}"/> + <waitForPageLoad stepKey="waitForProductTaxClassDeleted"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml index 42fd01357375e..7d954bd5e1ac2 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml @@ -8,6 +8,18 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SimpleTaxUK" type="tax"> + <data key="state">California</data> + <data key="country">United Kingdom</data> + <data key="zip">*</data> + <data key="rate">50</data> + </entity> + <entity name="SimpleTaxUKZeroRate" type="tax"> + <data key="state">California</data> + <data key="country">United Kingdom</data> + <data key="zip">*</data> + <data key="rate">0</data> + </entity> <entity name="SimpleTaxNY" type="tax"> <data key="state">New York</data> <data key="country">United States</data> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml index b3f341b687ba7..e11f856c5f57c 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml @@ -23,4 +23,10 @@ </array> <data key="calculate_subtotal">true</data> </entity> + <entity name="TaxRule" type="taxRule"> + <data key="name" unique="suffix">TaxName</data> + </entity> + <entity name="TaxRuleZeroRate" type="taxRule"> + <data key="name" unique="suffix">TaxNameZeroRate</data> + </entity> </entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml index 9727c649d7e66..539ec4eae11b6 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml @@ -10,6 +10,10 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminTaxRulesSection"> <!-- on page /admin/tax/rule/new/ --> + <element name="customerAddNewTaxClass" type="button" selector="//*[@id='tax_customer_class']/following-sibling::section//*[contains(text(),'Add New Tax Class')]"/> + <element name="fieldCustomerNewTaxClass" type="input" selector="//*[@id='tax_customer_class']/following-sibling::section//input[@class='mselect-input']"/> + <element name="saveCustomerNewTaxClass" type="button" selector="//*[@id='tax_customer_class']/following-sibling::section//span[@class='mselect-save']"/> + <element name="defaultCustomerTaxClass" type="button" selector="//*[@id='tax_customer_class']/following-sibling::section//div[@class='mselect-items-wrapper']/div[1]"/> <element name="ruleName" type="input" selector="#anchor-content #code"/> <element name="addNewTaxRate" type="block" selector="//*[text()='Add New Tax Rate']" timeout="30"/> <element name="taxIdentifier" type="input" selector="aside #code"/> From 6db1a827593a6a2196f0c711256cd5bbfc507ae1 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Tue, 2 Oct 2018 17:02:00 +0300 Subject: [PATCH 0130/1158] MAGETWO-95332: Update price in shopping cart after product save --- .../Mftf/Section/AdminMainActionsSection.xml | 4 +- .../Mftf/ActionGroup/CheckoutActionGroup.xml | 9 ++- .../Mftf/Section/CheckoutPaymentSection.xml | 7 +- .../Section/StorefrontMiniCartSection.xml | 1 + ...riceInShoppingCartAfterProductSaveTest.xml | 66 +++++++++++++++++++ .../AdminConfigCustomerActionGroup.xml | 20 ++++++ .../Mftf/Page/AdminCustomerConfigPage.xml | 12 ++++ .../Section/AdminCustomerConfigSection.xml | 12 ++++ 8 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminConfigCustomerActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerConfigPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml index cb164d43a49ff..bc576559e7a13 100644 --- a/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml +++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml @@ -9,7 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminMainActionsSection"> - <element name="save" type="button" selector="#save"/> - <element name="delete" type="button" selector="#delete"/> + <element name="save" type="button" selector="#save" timeout="30"/> + <element name="delete" type="button" selector="#delete" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index 32d6ad8667029..2e800cdb3fb8c 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -10,17 +10,16 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <!-- Go to checkout from minicart --> <actionGroup name="GoToCheckoutFromMinicartActionGroup"> - <wait stepKey="wait" time="10" /> + <waitForElementNotVisible selector="{{StorefrontMinicartSection.emptyCart}}" stepKey="waitUpdateQuantity" /> <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> <click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/> - <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> <!-- Guest checkout filling shipping section --> <actionGroup name="GuestCheckoutFillingShippingSectionActionGroup"> <arguments> - <argument name="customerVar"/> - <argument name="customerAddressVar"/> + <argument name="customerVar" defaultValue="CustomerEntityOne"/> + <argument name="customerAddressVar" defaultValue="CustomerAddressSimple"/> </arguments> <fillField selector="{{CheckoutShippingSection.email}}" userInput="{{customerVar.email}}" stepKey="enterEmail"/> <fillField selector="{{CheckoutShippingSection.firstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> @@ -161,4 +160,4 @@ <see userInput="You are signed out" stepKey="signOut"/> </actionGroup> -</actionGroups> \ No newline at end of file +</actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml index 7dda1110fd145..2a6a6bb6d2593 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml @@ -25,7 +25,7 @@ <element name="billingAddress" type="text" selector="div.billing-address-details"/> <element name="cartItems" type="text" selector="ol.minicart-items"/> <element name="cartItemsArea" type="button" selector="div.block.items-in-cart"/> - <element name="cartItemsAreaActive" type="textarea" selector="div.block.items-in-cart.active"/> + <element name="cartItemsAreaActive" type="textarea" selector="div.block.items-in-cart.active" timeout="30"/> <element name="checkMoneyOrderPayment" type="radio" selector="input#checkmo.radio" timeout="30"/> <element name="placeOrder" type="button" selector="button.action.primary.checkout" timeout="30"/> <element name="paymentSectionTitle" type="text" selector="//*[@id='checkout-payment-method-load']//div[text()='Payment Method']" /> @@ -40,8 +40,9 @@ <element name="shipToInformation" type="text" selector="//div[@class='ship-to']//div[@class='shipping-information-content']" /> <element name="shippingMethodInformation" type="text" selector="//div[@class='ship-via']//div[@class='shipping-information-content']" /> <element name="paymentMethodTitle" type="text" selector=".payment-method-title span" /> - <element name="productOptionsByProductItemPrice" type="text" selector="//div[@class='product-item-inner']//div[@class='subtotal']//span[@class='price'][contains(.,'{{var1}}')]//ancestor::div[@class='product-item-details']//div[@class='product options']" parameterized="true"/> - <element name="productOptionsActiveByProductItemPrice" type="text" selector="//div[@class='subtotal']//span[@class='price'][contains(.,'{{var1}}')]//ancestor::div[@class='product-item-details']//div[@class='product options active']" parameterized="true"/> + <element name="productOptionsByProductItemPrice" type="text" selector="//div[@class='product-item-inner']//div[@class='subtotal']//span[@class='price'][contains(.,'{{price}}')]//ancestor::div[@class='product-item-details']//div[@class='product options']" parameterized="true"/> + <element name="productOptionsActiveByProductItemPrice" type="text" selector="//div[@class='subtotal']//span[@class='price'][contains(.,'{{price}}')]//ancestor::div[@class='product-item-details']//div[@class='product options active']" parameterized="true"/> + <element name="productItemPriceByName" type="text" selector="//div[@class='product-item-details'][contains(., '{{ProductName}}')]//span[@class='price']" parameterized="true"/> <element name="tax" type="text" selector="[data-th='Tax'] span" timeout="30"/> <element name="taxPercentage" type="text" selector=".totals-tax-details .mark"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml index c8ff851ae54ab..ccb626d4e1e41 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml @@ -27,5 +27,6 @@ <element name="itemQuantityUpdate" type="button" selector="//a[text()='{{productName}}']/../..//span[text()='Update']" parameterized="true"/> <element name="itemDiscount" type="text" selector="//tr[@class='totals']//td[@class='amount']/span"/> <element name="subtotal" type="text" selector="//tr[@class='totals sub']//td[@class='amount']/span"/> + <element name="emptyCart" type="text" selector=".counter.qty.empty"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml new file mode 100644 index 0000000000000..91f9cbf398d24 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontUpdatePriceInShoppingCartAfterProductSaveTest"> + <annotations> + <features value="Checkout"/> + <stories value="Checkout via the Storefront"/> + <title value="Update price in shopping cart after product save"/> + <description value="Price in shopping cart should be updated after product save with changed price"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-58179"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="SimpleProduct2" stepKey="createSimpleProduct"> + <field key="price">100</field> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SetCustomerDataLifetimeActionGroup" stepKey="setCustomerDataLifetime"> + <argument name="minutes" value="1"/> + </actionGroup> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="SetCustomerDataLifetimeActionGroup" stepKey="setDefaultCustomerDataLifetime"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!--Go to product page--> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.custom_attributes[url_key]$$)}}" stepKey="navigateToSimpleProductPage"/> + + <!--Add Product to Shopping Cart--> + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$$createSimpleProduct.name$$"/> + </actionGroup> + + <!--Go to Checkout--> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart"/> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShipping"/> + + <!--Check price--> + <conditionalClick selector="{{CheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{CheckoutPaymentSection.cartItemsAreaActive}}" visible="false" stepKey="openItemProductBlock"/> + <see userInput="$100.00" selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" stepKey="checkSummarySubtotal"/> + <see userInput="$100.00" selector="{{CheckoutPaymentSection.productItemPriceByName($$createSimpleProduct.name$$)}}" stepKey="checkItemPrice"/> + + <!--Edit product price via admin panel--> + <openNewTab stepKey="openNewTab"/> + <amOnPage url="{{AdminProductEditPage.url($$createSimpleProduct.id$$)}}" stepKey="goToProductEditPage"/> + <fillField userInput="120" selector="{{AdminProductFormSection.productPrice}}" stepKey="setNewPrice"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + <closeTab stepKey="closeTab"/> + + <!--Check price--> + <reloadPage stepKey="reloadPage"/> + <waitForPageLoad stepKey="waitForCheckoutPageReload"/> + <conditionalClick selector="{{CheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{CheckoutPaymentSection.cartItemsAreaActive}}" visible="false" stepKey="openItemProductBlock1"/> + <see userInput="$120.00" selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" stepKey="checkSummarySubtotal1"/> + <see userInput="$120.00" selector="{{CheckoutPaymentSection.productItemPriceByName($$createSimpleProduct.name$$)}}" stepKey="checkItemPrice1"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminConfigCustomerActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminConfigCustomerActionGroup.xml new file mode 100644 index 0000000000000..8a3ab7068696c --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminConfigCustomerActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="SetCustomerDataLifetimeActionGroup"> + <arguments> + <argument name="minutes" defaultValue="60" type="string"/> + </arguments> + <amOnPage url="{{AdminCustomerConfigPage.url('#customer_online_customers-link')}}" stepKey="openCustomerConfigPage"/> + <fillField userInput="{{minutes}}" selector="{{AdminCustomerConfigSection.customerDataLifetime}}" stepKey="fillCustomerDataLifetime"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSave"/> + <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerConfigPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerConfigPage.xml new file mode 100644 index 0000000000000..282f9bb6fdeb5 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerConfigPage.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminCustomerConfigPage" url="admin/system_config/edit/section/customer/{{tabLink}}" area="admin" parameterized="true" module="Magento_Customer"> + <section name="AdminCustomerConfigSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml new file mode 100644 index 0000000000000..9e104eb52cf90 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCustomerConfigSection"> + <element name="customerDataLifetime" type="input" selector="#customer_online_customers_section_data_lifetime"/> + </section> +</sections> From 5f9a9901530d8023b6756a0a73a2a9c7a4c1ee35 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Tue, 28 Aug 2018 13:38:50 +0300 Subject: [PATCH 0131/1158] MAGETWO-91569: Special characters in CSV return error: General system exception happened - Added message to "Select File to Import" field in import form --- .../ImportExport/Block/Adminhtml/Import/Edit/Form.php | 5 ++++- .../CatalogImportExport/_files/product_export_data.php | 2 +- .../_files/product_export_data_special_chars.php | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php index 39d0d5c7feaee..8fd73e466083a 100644 --- a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php +++ b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php @@ -212,7 +212,10 @@ protected function _prepareForm() 'label' => __('Select File to Import'), 'title' => __('Select File to Import'), 'required' => true, - 'class' => 'input-file' + 'class' => 'input-file', + 'note' => __( + 'File must be saved in UTF-8 encoding for proper import' + ), ] ); $fieldsets['upload']->addField( diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php index 89fb9952cc6f1..477494626b9fb 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data.php @@ -70,7 +70,7 @@ )->setPrice( 10 )->addData( - ['text_attribute' => '!@#$%^&*()_+1234567890-=|\\:;"\'<,>.?/'] + ['text_attribute' => '!@#$%^&*()_+1234567890-=|\\:;"\'<,>.?/›ƒª'] )->setTierPrice( [0 => ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 8]] )->setVisibility( diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars.php index a2c2c1815a8a9..591dccf229f89 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars.php @@ -25,7 +25,7 @@ ->setName('New Product') ->setSku('simple "1"') ->setPrice(10) - ->addData(['text_attribute' => '!@#$%^&*()_+1234567890-=|\\:;"\'<,>.?/']) + ->addData(['text_attribute' => '!@#$%^&*()_+1234567890-=|\\:;"\'<,>.?/›ƒª']) ->setTierPrice([0 => ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 8]]) ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) From 7400261ffcb052625070cf79a2d75f60282590cd Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Wed, 3 Oct 2018 13:17:04 +0300 Subject: [PATCH 0132/1158] MAGETWO-93769: Catalog performance improvements --- .../Model/Product/Price/TierPriceStorage.php | 21 ++++++++++--------- .../Catalog/Model/ProductIdLocator.php | 15 +++++++++++-- .../ResourceModel/Product/Collection.php | 10 ++++++++- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php b/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php index 1bddd2d07cd81..7298e650bd448 100644 --- a/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php +++ b/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php @@ -171,16 +171,17 @@ private function getExistingPrices(array $skus, $groupBySku = false) $ids = $this->retrieveAffectedIds($skus); $rawPrices = $this->tierPricePersistence->get($ids); $prices = []; - - $linkField = $this->tierPricePersistence->getEntityLinkField(); - $skuByIdLookup = $this->buildSkuByIdLookup($skus); - foreach ($rawPrices as $rawPrice) { - $sku = $skuByIdLookup[$rawPrice[$linkField]]; - $price = $this->tierPriceFactory->create($rawPrice, $sku); - if ($groupBySku) { - $prices[$sku][] = $price; - } else { - $prices[] = $price; + if ($rawPrices) { + $linkField = $this->tierPricePersistence->getEntityLinkField(); + $skuByIdLookup = $this->buildSkuByIdLookup($skus); + foreach ($rawPrices as $rawPrice) { + $sku = $skuByIdLookup[$rawPrice[$linkField]]; + $price = $this->tierPriceFactory->create($rawPrice, $sku); + if ($groupBySku) { + $prices[$sku][] = $price; + } else { + $prices[] = $price; + } } } diff --git a/app/code/Magento/Catalog/Model/ProductIdLocator.php b/app/code/Magento/Catalog/Model/ProductIdLocator.php index 2d9af6829ad6e..ba8fa01b40f58 100644 --- a/app/code/Magento/Catalog/Model/ProductIdLocator.php +++ b/app/code/Magento/Catalog/Model/ProductIdLocator.php @@ -37,6 +37,11 @@ class ProductIdLocator implements \Magento\Catalog\Model\ProductIdLocatorInterfa */ private $idsBySku = []; + /** + * Page size to iterate collection + */ + private $pageSize = 10000; + /** * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory @@ -72,8 +77,14 @@ public function retrieveProductIdsBySkus(array $skus) $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) ->getLinkField(); - foreach ($collection as $item) { - $this->idsBySku[strtolower(trim($item->getSku()))][$item->getData($linkField)] = $item->getTypeId(); + $collection->setPageSize($this->pageSize); + $pages = $collection->getLastPageNumber(); + for ($currentPage = 1; $currentPage <= $pages; $currentPage++) { + $collection->setCurPage($currentPage); + foreach ($collection->getItems() as $item) { + $this->idsBySku[strtolower(trim($item->getSku()))][$item->getData($linkField)] = $item->getTypeId(); + } + $collection->clear(); } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php index fdd98442150ae..4aa427223dcbe 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php @@ -290,6 +290,11 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac */ private $dimensionFactory; + /** + * @var \Magento\Framework\DataObject + */ + private $emptyItem; + /** * Collection constructor * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory @@ -550,7 +555,10 @@ protected function _prepareStaticFields() */ public function getNewEmptyItem() { - $object = parent::getNewEmptyItem(); + if (null === $this->emptyItem) { + $this->emptyItem = parent::getNewEmptyItem(); + } + $object = clone $this->emptyItem; if ($this->isEnabledFlat()) { $object->setIdFieldName($this->getEntity()->getIdFieldName()); } From 057f1209bcd739e14837a9e7bec91d615505174a Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun <ogorkun@magento.com> Date: Wed, 3 Oct 2018 13:41:20 +0300 Subject: [PATCH 0133/1158] MAGETWO-94121: Independent blocks rule --- .../Rule/Design/RequestAwareBlockMethod.php | 53 +++++++++++++++++++ .../resources/rulesets/design.xml | 31 +++++++++++ .../Magento/Test/Php/_files/phpmd/ruleset.xml | 1 + 3 files changed, 85 insertions(+) create mode 100644 dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/RequestAwareBlockMethod.php diff --git a/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/RequestAwareBlockMethod.php b/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/RequestAwareBlockMethod.php new file mode 100644 index 0000000000000..9ce891da718b4 --- /dev/null +++ b/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/RequestAwareBlockMethod.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\CodeMessDetector\Rule\Design; + +use PHPMD\AbstractNode; +use PHPMD\AbstractRule; +use PHPMD\Node\ClassNode; +use PHPMD\Node\MethodNode; +use PDepend\Source\AST\ASTMethod; +use PHPMD\Rule\MethodAware; + +/** + * Detect direct request usages. + */ +class RequestAwareBlockMethod extends AbstractRule implements MethodAware +{ + /** + * @inheritDoc + * + * @param ASTMethod|MethodNode $method + */ + public function apply(AbstractNode $method) + { + $definedIn = $method->getParentType(); + try { + $isBlock = ($definedIn instanceof ClassNode) + && is_subclass_of( + $definedIn->getFullQualifiedName(), + \Magento\Framework\View\Element\AbstractBlock::class + ); + } catch (\Throwable $exception) { + //Failed to load classes. + return; + } + + if ($isBlock) { + $nodes = $method->findChildrenOfType('PropertyPostfix') + $method->findChildrenOfType('MethodPostfix'); + foreach ($nodes as $node) { + $name = mb_strtolower($node->getFirstChildOfType('Identifier')->getImage()); + if ($name === '_request' || $name === 'getrequest') { + $this->addViolation($method, [$method->getFullQualifiedName()]); + break; + } + } + } + } +} diff --git a/dev/tests/static/framework/Magento/CodeMessDetector/resources/rulesets/design.xml b/dev/tests/static/framework/Magento/CodeMessDetector/resources/rulesets/design.xml index c9bfe4fe6e308..100e08276e6cf 100644 --- a/dev/tests/static/framework/Magento/CodeMessDetector/resources/rulesets/design.xml +++ b/dev/tests/static/framework/Magento/CodeMessDetector/resources/rulesets/design.xml @@ -54,6 +54,37 @@ class PostOrder implements ActionInterface ... return $response; } +} + ]]> + </example> + </rule> + <rule name="RequestAwareBlockMethod" + class="Magento\CodeMessDetector\Rule\Design\RequestAwareBlockMethod" + message="{0} uses request object directly. Add user input validation and suppress this warning."> + <description> + <![CDATA[ +Blocks must not depend on being used with certain controllers. +If you use request object in a block directly you must validate all user input inside the block. + ]]> + </description> + <priority>2</priority> + <properties /> + <example> + <![CDATA[ +class MyOrder extends AbstractBlock +{ + + ....... + + public function getOrder() + { + $orderId = $this->getRequest()->getParam('order_id'); + //Validate customer having such order. + if (!$this->hasOrder($this->getCustomerId(), $orderId)) { + ...deny access... + } + ..... + } } ]]> </example> diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml index fddb1e6fdfc14..2d9eb7478ce91 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml @@ -48,5 +48,6 @@ <!-- Magento Specific Rules --> <rule ref="Magento/CodeMessDetector/resources/rulesets/design.xml/FinalImplementation" /> <rule ref="Magento/CodeMessDetector/resources/rulesets/design.xml/AllPurposeAction" /> + <rule ref="Magento/CodeMessDetector/resources/rulesets/design.xml/RequestAwareBlockMethod" /> </ruleset> From 7c5962a43c38024275530ba71215acdd9573bbb5 Mon Sep 17 00:00:00 2001 From: vprohorov <prohorov.vital@gmail.com> Date: Wed, 19 Sep 2018 02:57:08 +0300 Subject: [PATCH 0134/1158] MAGETWO-91684: Issue with Newsletter subscriptions - Changing subscription behavior to websites --- .../Model/ResourceModel/Subscriber.php | 43 ++++++++++--------- .../Magento/Newsletter/Model/Subscriber.php | 3 ++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php index b6e53b3695f78..100d179cbb60e 100644 --- a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php @@ -5,6 +5,9 @@ */ namespace Magento\Newsletter\Model\ResourceModel; +use Magento\Framework\App\ObjectManager; +use Magento\Store\Model\StoreManagerInterface; + /** * Newsletter subscriber resource model * @@ -48,6 +51,11 @@ class Subscriber extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb */ protected $mathRandom; + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * Construct * @@ -55,15 +63,18 @@ class Subscriber extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb * @param \Magento\Framework\Stdlib\DateTime\DateTime $date * @param \Magento\Framework\Math\Random $mathRandom * @param string $connectionName + * @param StoreManagerInterface $storeManager */ public function __construct( \Magento\Framework\Model\ResourceModel\Db\Context $context, \Magento\Framework\Stdlib\DateTime\DateTime $date, \Magento\Framework\Math\Random $mathRandom, - $connectionName = null + $connectionName = null, + StoreManagerInterface $storeManager = null ) { $this->_date = $date; $this->mathRandom = $mathRandom; + $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); parent::__construct($context, $connectionName); } @@ -117,19 +128,15 @@ public function loadByEmail($subscriberEmail) */ public function loadByCustomerData(\Magento\Customer\Api\Data\CustomerInterface $customer) { + $storeIds = $this->storeManager->getWebsite($customer->getWebsiteId())->getStoreIds(); + $select = $this->connection ->select() ->from($this->getMainTable()) - ->where('customer_id=:customer_id and store_id=:store_id'); - - $result = $this->connection - ->fetchRow( - $select, - [ - 'customer_id' => $customer->getId(), - 'store_id' => $customer->getStoreId() - ] - ); + ->where('customer_id = ?', $customer->getId()) + ->where('store_id IN (?)', $storeIds); + + $result = $this->connection->fetchRow($select); if ($result) { return $result; @@ -138,16 +145,10 @@ public function loadByCustomerData(\Magento\Customer\Api\Data\CustomerInterface $select = $this->connection ->select() ->from($this->getMainTable()) - ->where('subscriber_email=:subscriber_email and store_id=:store_id'); - - $result = $this->connection - ->fetchRow( - $select, - [ - 'subscriber_email' => $customer->getEmail(), - 'store_id' => $customer->getStoreId() - ] - ); + ->where('subscriber_email = ?', $customer->getEmail()) + ->where('store_id IN (?)', $storeIds); + + $result = $this->connection->fetchRow($select); if ($result) { return $result; diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php index 03976dfcdc197..9611e4b67f1e2 100644 --- a/app/code/Magento/Newsletter/Model/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/Subscriber.php @@ -392,6 +392,9 @@ public function loadByCustomerId($customerId) try { $customerData = $this->customerRepository->getById($customerId); $customerData->setStoreId($this->_storeManager->getStore()->getId()); + if ($customerData->getWebsiteId() === null) { + $customerData->setWebsiteId($this->_storeManager->getStore()->getWebsiteId()); + } $data = $this->getResource()->loadByCustomerData($customerData); $this->addData($data); if (!empty($data) && $customerData->getId() && !$this->getCustomerId()) { From 9ff3f48412067730c9926bf6354d896d4b21f4a8 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 3 Oct 2018 13:47:29 +0300 Subject: [PATCH 0135/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Magento/Backend/Block/Media/Uploader.php | 26 +++++-- .../Backend/Model/Image/ImageUploadConfig.php | 72 +++++++++++++++++++ .../Image/ImageUploadConfigInterface.php | 37 ++++++++++ app/code/Magento/Backend/etc/adminhtml/di.xml | 1 + .../Magento/Backend/etc/adminhtml/system.xml | 15 +++- app/code/Magento/Backend/etc/config.xml | 1 + .../adminhtml/templates/media/uploader.phtml | 3 +- .../view/adminhtml/web/js/media-uploader.js | 16 +++-- .../Magento/Framework/File/Uploader.php | 4 +- .../Framework/Image/Adapter/Config.php | 12 ++++ .../Image/Adapter/UploadConfigInterface.php | 2 + 11 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 app/code/Magento/Backend/Model/Image/ImageUploadConfig.php create mode 100644 app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php index eb98808dd644b..6962141c465b8 100644 --- a/app/code/Magento/Backend/Block/Media/Uploader.php +++ b/app/code/Magento/Backend/Block/Media/Uploader.php @@ -10,6 +10,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\Image\Adapter\UploadConfigInterface; +use Magento\Backend\Model\Image\ImageUploadConfigInterface; /** * Adminhtml media library uploader @@ -39,9 +40,9 @@ class Uploader extends \Magento\Backend\Block\Widget private $jsonEncoder; /** - * @var UploadConfigInterface + * @var ImageUploadConfigInterface */ - private $imageConfig; + private $imageUploadConfig; /** * @param \Magento\Backend\Block\Template\Context $context @@ -49,18 +50,19 @@ class Uploader extends \Magento\Backend\Block\Widget * @param array $data * @param Json $jsonEncoder * @param UploadConfigInterface $imageConfig + * @param ImageUploadConfigInterface $imageUploadConfig */ public function __construct( \Magento\Backend\Block\Template\Context $context, \Magento\Framework\File\Size $fileSize, array $data = [], Json $jsonEncoder = null, - UploadConfigInterface $imageConfig = null + UploadConfigInterface $imageConfig = null, + ImageUploadConfigInterface $imageUploadConfig = null ) { $this->_fileSizeService = $fileSize; $this->jsonEncoder = $jsonEncoder ?: ObjectManager::getInstance()->get(Json::class); - $this->imageConfig = $imageConfig ?: ObjectManager::getInstance()->get(UploadConfigInterface::class); - + $this->imageUploadConfig = $imageUploadConfig ?: ObjectManager::getInstance()->get(UploadConfigInterface::class); parent::__construct($context, $data); } @@ -111,7 +113,7 @@ public function getFileSizeService() */ public function getImageUploadMaxWidth() { - return $this->imageConfig->getMaxWidth(); + return $this->imageUploadConfig->getMaxWidth(); } /** @@ -121,7 +123,17 @@ public function getImageUploadMaxWidth() */ public function getImageUploadMaxHeight() { - return $this->imageConfig->getMaxHeight(); + return $this->imageUploadConfig->getMaxHeight(); + } + + /** + * Get image resize configuration + * + * @return bool + */ + public function getIsResizeEnabled(): bool + { + return $this->imageUploadConfig->isResizeEnabled(); } /** diff --git a/app/code/Magento/Backend/Model/Image/ImageUploadConfig.php b/app/code/Magento/Backend/Model/Image/ImageUploadConfig.php new file mode 100644 index 0000000000000..b7e13b1e8274c --- /dev/null +++ b/app/code/Magento/Backend/Model/Image/ImageUploadConfig.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Backend\Model\Image; + +/** + * Image uploader config provider. + */ +class ImageUploadConfig implements ImageUploadConfigInterface +{ + /** + * Config path for the maximal image width value + */ + const XML_PATH_MAX_WIDTH_IMAGE = 'system/upload_configuration/max_width'; + + /** + * Config path for the maximal image height value + */ + const XML_PATH_MAX_HEIGHT_IMAGE = 'system/upload_configuration/max_height'; + + /** + * Config path for the maximal image height value + */ + const XML_PATH_ENABLE_RESIZE = 'system/upload_configuration/enable_resize'; + + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface + */ + private $config; + + /** + * @param \Magento\Framework\App\Config\ScopeConfigInterface $config + */ + public function __construct(\Magento\Framework\App\Config\ScopeConfigInterface $config) + { + $this->config = $config; + } + + /** + * Get maximal width value for resized image + * + * @return int + */ + public function getMaxWidth(): int + { + return (int)$this->config->getValue(self::XML_PATH_MAX_WIDTH_IMAGE); + } + + /** + * Get maximal height value for resized image + * + * @return int + */ + public function getMaxHeight(): int + { + return (int)$this->config->getValue(self::XML_PATH_MAX_HEIGHT_IMAGE); + } + + /** + * Get config value for frontend resize + * + * @return bool + */ + public function isResizeEnabled(): bool + { + return (bool)$this->config->getValue(self::XML_PATH_ENABLE_RESIZE); + } +} diff --git a/app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php b/app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php new file mode 100644 index 0000000000000..254a13407b2c1 --- /dev/null +++ b/app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Backend\Model\Image; + +/** + * Interface ImageUploadConfigInterface + * + * Used to retrieve configuration for frontend image uploader + */ +interface ImageUploadConfigInterface +{ + /** + * Get maximal width value for resized image + * + * @return int + */ + public function getMaxWidth(): int; + + /** + * Get maximal height value for resized image + * + * @return int + */ + public function getMaxHeight(): int; + + /** + * Get config value for frontend resize + * + * @return bool + */ + public function isResizeEnabled(): bool; +} diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml index 3384384343fe9..dcfc99cfed310 100644 --- a/app/code/Magento/Backend/etc/adminhtml/di.xml +++ b/app/code/Magento/Backend/etc/adminhtml/di.xml @@ -168,4 +168,5 @@ </arguments> </type> <preference for="CsrfRequestValidator" type="Magento\Backend\App\Request\BackendValidator" /> + <preference for="Magento\Backend\Model\Image\ImageUploadConfigInterface" type="Magento\Backend\Model\Image\ImageUploadConfig" /> </config> diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml index e061455acbe6b..3a0d3e50acc5a 100644 --- a/app/code/Magento/Backend/etc/adminhtml/system.xml +++ b/app/code/Magento/Backend/etc/adminhtml/system.xml @@ -338,15 +338,26 @@ </group> <group id="upload_configuration" translate="label" type="text" sortOrder="1000" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Images Upload Configuration</label> - <field id="max_width" translate="label comment" type="text" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <field id="enable_resize" translate="label" type="select" sortOrder="200" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <label>Enable Front-end Resize</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <comment>Resize performed by javascript during file upload.</comment> + </field> + <field id="max_width" translate="label comment" type="text" sortOrder="300" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Maximum Width</label> <validate>validate-greater-than-zero validate-number required-entry</validate> <comment>Maximum allowed width for uploaded image.</comment> + <depends> + <field id="enable_resize">1</field> + </depends> </field> - <field id="max_height" translate="label comment" type="text" sortOrder="200" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <field id="max_height" translate="label comment" type="text" sortOrder="400" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Maximum Height</label> <validate>validate-greater-than-zero validate-number required-entry</validate> <comment>Maximum allowed height for uploaded image.</comment> + <depends> + <field id="enable_resize">1</field> + </depends> </field> </group> </section> diff --git a/app/code/Magento/Backend/etc/config.xml b/app/code/Magento/Backend/etc/config.xml index 45d283ad3ff22..8283fa18dd370 100644 --- a/app/code/Magento/Backend/etc/config.xml +++ b/app/code/Magento/Backend/etc/config.xml @@ -29,6 +29,7 @@ <enable_charts>1</enable_charts> </dashboard> <upload_configuration> + <enable_resize>1</enable_resize> <max_width>1920</max_width> <max_height>1200</max_height> </upload_configuration> diff --git a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml index 966372773f295..edd54ae38b6a1 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml @@ -14,7 +14,8 @@ "Magento_Backend/js/media-uploader" : { "maxFileSize": <?= /* @escapeNotVerified */ $block->getFileSizeService()->getMaxFileSize() ?>, "maxWidth":<?= /* @escapeNotVerified */ $block->getImageUploadMaxWidth() ?> , - "maxHeight": <?= /* @escapeNotVerified */ $block->getImageUploadMaxHeight() ?> + "maxHeight": <?= /* @escapeNotVerified */ $block->getImageUploadMaxHeight() ?>, + "isResizeEnabled": <?= /* @noEscape */ $block->getIsResizeEnabled() ?> } }' > diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js index 7e0b6bdfb46dd..35e9ec244df24 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js @@ -35,7 +35,10 @@ define([ _create: function () { var self = this, - progressTmpl = mageTemplate('[data-template="uploader"]'); + progressTmpl = mageTemplate('[data-template="uploader"]'), + resizeConfig = { + action: 'resize' + }; this.element.find('input[type=file]').fileupload({ dataType: 'json', @@ -120,14 +123,19 @@ define([ stop: fileUploader.uploaderConfig.stop }); + if (typeof this.options.isResizeEnabled !== 'undefined' && this.options.isResizeEnabled === true) { + resizeConfig.maxWidth = this.options.maxWidth; + resizeConfig.maxHeight = this.options.maxHeight; + } + this.element.find('input[type=file]').fileupload('option', { process: [{ action: 'load', fileTypes: /^image\/(gif|jpeg|png)$/, maxFileSize: this.options.maxFileSize - }, { - action: 'resize' - }, { + }, + resizeConfig, + { action: 'save' }] }); diff --git a/lib/internal/Magento/Framework/File/Uploader.php b/lib/internal/Magento/Framework/File/Uploader.php index 9a6787ddbaffd..0785177042451 100644 --- a/lib/internal/Magento/Framework/File/Uploader.php +++ b/lib/internal/Magento/Framework/File/Uploader.php @@ -140,14 +140,14 @@ class Uploader * @deprecated * @see \Magento\Framework\Image\Adapter\UploadConfigInterface::getMaxWidth() */ - const MAX_IMAGE_WIDTH = 4096; + const MAX_IMAGE_WIDTH = 1920; /** * Maximum Image Height resolution in pixels. For image resizing on client side * @deprecated * @see \Magento\Framework\Image\Adapter\UploadConfigInterface::getMaxHeight() */ - const MAX_IMAGE_HEIGHT = 2160; + const MAX_IMAGE_HEIGHT = 1200; /** * Resulting of uploaded file diff --git a/lib/internal/Magento/Framework/Image/Adapter/Config.php b/lib/internal/Magento/Framework/Image/Adapter/Config.php index a159bc9ffd448..84b6b6dcfbdd1 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Config.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Config.php @@ -16,8 +16,16 @@ class Config implements ConfigInterface, UploadConfigInterface const XML_PATH_IMAGE_ADAPTERS = 'dev/image/adapters'; + /** + * Config path for the maximal image width value + * @deprecated + */ const XML_PATH_MAX_WIDTH_IMAGE = 'system/upload_configuration/max_width'; + /** + * Config path for the maximal image height value + * @deprecated + */ const XML_PATH_MAX_HEIGHT_IMAGE = 'system/upload_configuration/max_height'; /** @@ -57,6 +65,8 @@ public function getAdapters() * Get Maximum Image Width resolution in pixels. For image resizing on client side. * * @return int + * @deprecated + * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface::getMaxHeight() */ public function getMaxWidth(): int { @@ -67,6 +77,8 @@ public function getMaxWidth(): int * Get Maximum Image Height resolution in pixels. For image resizing on client side. * * @return int + * @deprecated + * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface::getMaxHeight() */ public function getMaxHeight(): int { diff --git a/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php b/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php index c42879060b0b2..990062b83ef6f 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php +++ b/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php @@ -9,6 +9,8 @@ /** * Interface UploadConfigInterface + * @deprecated because new interface was introduced + * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface; */ interface UploadConfigInterface { From cad023ddcb808eee009a0e1addbe6ba2ce80cbdd Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Wed, 3 Oct 2018 13:53:13 +0300 Subject: [PATCH 0136/1158] MAGETWO-56094: Header issue when resizing in Internet Explorer - Fixed css styles for page-actions div elements --- .../Magento_Backend/web/css/source/module/main/_actions-bar.less | 1 - 1 file changed, 1 deletion(-) diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less index 07050c1e5111d..08434727ccc9c 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less @@ -44,7 +44,6 @@ .page-actions { @_page-action__indent: 1.3rem; - float: right; .page-main-actions & { &._fixed { From e5a30aab22728751c8a79a1d0062f4e2206766e4 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 3 Oct 2018 14:32:22 +0300 Subject: [PATCH 0137/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- app/code/Magento/Backend/Block/Media/Uploader.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php index 6962141c465b8..1995d72661e2e 100644 --- a/app/code/Magento/Backend/Block/Media/Uploader.php +++ b/app/code/Magento/Backend/Block/Media/Uploader.php @@ -62,7 +62,8 @@ public function __construct( ) { $this->_fileSizeService = $fileSize; $this->jsonEncoder = $jsonEncoder ?: ObjectManager::getInstance()->get(Json::class); - $this->imageUploadConfig = $imageUploadConfig ?: ObjectManager::getInstance()->get(UploadConfigInterface::class); + $this->imageUploadConfig = $imageUploadConfig + ?: ObjectManager::getInstance()->get(ImageUploadConfigInterface::class); parent::__construct($context, $data); } From 7547dd2e0a66d66fc0ed1b4dcb2ccd9de792a6b4 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Wed, 3 Oct 2018 15:38:50 +0300 Subject: [PATCH 0138/1158] MAGETWO-91750: Multiselect attribute values is not searchable under Quick Search when more than one value is selected - Added possibility to retrieve multiselect option values for catalog fulltext search reindexation --- .../Indexer/Fulltext/Action/DataProvider.php | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index 83058b6f0ad55..3882921680a42 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -12,6 +12,8 @@ use Magento\Store\Model\Store; /** + * Data provider class + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.TooManyFields) * @api @@ -570,8 +572,8 @@ public function prepareProductIndex($indexData, $productData, $storeId) } } foreach ($indexData as $entityId => $attributeData) { - foreach ($attributeData as $attributeId => $attributeValue) { - $value = $this->getAttributeValue($attributeId, $attributeValue, $storeId); + foreach ($attributeData as $attributeId => $attributeValues) { + $value = $this->getAttributeValue($attributeId, $attributeValues, $storeId); if (!empty($value)) { if (isset($index[$attributeId])) { $index[$attributeId][$entityId] = $value; @@ -602,16 +604,16 @@ public function prepareProductIndex($indexData, $productData, $storeId) * Retrieve attribute source value for search * * @param int $attributeId - * @param mixed $valueId + * @param mixed $valueIds * @param int $storeId * @return string */ - private function getAttributeValue($attributeId, $valueId, $storeId) + private function getAttributeValue($attributeId, $valueIds, $storeId) { $attribute = $this->getSearchableAttribute($attributeId); - $value = $this->engine->processAttributeValue($attribute, $valueId); + $value = $this->engine->processAttributeValue($attribute, $valueIds); if (false !== $value) { - $optionValue = $this->getAttributeOptionValue($attributeId, $valueId, $storeId); + $optionValue = $this->getAttributeOptionValue($attributeId, $valueIds, $storeId); if (null === $optionValue) { $value = $this->filterAttributeValue($value); } else { @@ -626,13 +628,15 @@ private function getAttributeValue($attributeId, $valueId, $storeId) * Get attribute option value * * @param int $attributeId - * @param int $valueId + * @param int|string $valueIds * @param int $storeId * @return null|string */ - private function getAttributeOptionValue($attributeId, $valueId, $storeId) + private function getAttributeOptionValue($attributeId, $valueIds, $storeId) { $optionKey = $attributeId . '-' . $storeId; + $attributeValueIds = explode(',', $valueIds); + $attributeOptionValue = ''; if (!array_key_exists($optionKey, $this->attributeOptions) ) { $attribute = $this->getSearchableAttribute($attributeId); @@ -650,8 +654,10 @@ private function getAttributeOptionValue($attributeId, $valueId, $storeId) $this->attributeOptions[$optionKey] = null; } } - - return $this->attributeOptions[$optionKey][$valueId] ?? null; + foreach ($attributeValueIds as $attrValueId) { + $attributeOptionValue .= $this->attributeOptions[$optionKey][$attrValueId] . ' '; + } + return empty($attributeOptionValue) ? null : trim($attributeOptionValue); } /** From 94ce40832e4c405f22a748ff8445c1b5777589a1 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Wed, 3 Oct 2018 17:44:23 +0300 Subject: [PATCH 0139/1158] MAGETWO-91649: #13513: Magento ignore store-level url_key of child category in URL rewrite process for global scope - Fixed codestyle issue in 'ChildrenUrlRewriteGenerator'; --- .../Model/Category/ChildrenUrlRewriteGenerator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php index f6049bbff02c4..d18034220cfa8 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php @@ -71,7 +71,8 @@ public function __construct( public function generate($storeId, Category $category, $rootCategoryId = null) { $mergeDataProvider = clone $this->mergeDataProviderPrototype; - if ($childrenIds = $this->childrenCategoriesProvider->getChildrenIds($category, true)) { + $childrenIds = $this->childrenCategoriesProvider->getChildrenIds($category, true); + if ($childrenIds) { foreach ($childrenIds as $childId) { /** @var Category $childCategory */ $childCategory = $this->categoryRepository->get($childId, $storeId); From 24672336afc2a748ab6f221a534f93ff1e894fdd Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Wed, 3 Oct 2018 18:00:18 +0200 Subject: [PATCH 0140/1158] Concept for setting shipping method only for single address checkout --- .../SetShippingMethodsOnCart.php | 111 +++++++++++------- .../Magento/QuoteGraphQl/etc/schema.graphqls | 5 +- 2 files changed, 71 insertions(+), 45 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php index 448bdcbb37a6d..f2e1be3bb0508 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php @@ -7,44 +7,63 @@ namespace Magento\QuoteGraphQl\Model\Resolver\ShippingMethod; +use Magento\Framework\Exception\CouldNotSaveException; +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Exception\StateException; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\Stdlib\ArrayManager; -use Magento\Quote\Api\CartRepositoryInterface; -use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use Magento\Quote\Model\ShippingMethodManagementInterface; +use Magento\QuoteGraphQl\Model\Authorization\IsCartMutationAllowedForCurrentUser; +/** + * Class SetShippingMethodsOnCart + * + * Mutation resolver for setting shipping methods for shopping cart + */ class SetShippingMethodsOnCart implements ResolverInterface { - /** - * @var CartRepositoryInterface - */ - private $cartRepository; - /** * @var MaskedQuoteIdToQuoteIdInterface */ private $maskedQuoteIdToQuoteId; - /** * @var ArrayManager */ private $arrayManager; + /** + * @var ShippingMethodManagementInterface + */ + private $shippingMethodManagement; + + /** + * @var IsCartMutationAllowedForCurrentUser + */ + private $isCartMutationAllowedForCurrentUser; + /** * SetShippingMethodsOnCart constructor. * @param ArrayManager $arrayManager * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + * @param ShippingMethodManagementInterface $shippingMethodManagement */ public function __construct( ArrayManager $arrayManager, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - CartRepositoryInterface $cartRepository + ShippingMethodManagementInterface $shippingMethodManagement, + IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser ) { $this->arrayManager = $arrayManager; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->cartRepository = $cartRepository; + $this->shippingMethodManagement = $shippingMethodManagement; + $this->isCartMutationAllowedForCurrentUser = $isCartMutationAllowedForCurrentUser; } /** @@ -56,50 +75,56 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $maskedCartId = $this->arrayManager->get('input/cart_id', $args); if (!$maskedCartId) { - // TODO: throw an exception + throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); } if (!$shippingMethods) { - // TODO: throw an exception? + throw new GraphQlInputException(__('Required parameter "shipping_methods" is missing')); } - foreach ($shippingMethods as $shippingMethod) { - if (empty($shippingMethod['cart_address_id'])) { - // TODO: throw input exception - } - - if (empty($shippingMethod['shipping_method_code'])) { - // TODO: throw input exception - } + $shippingMethod = reset($shippingMethods); // TODO: provide implementation for multishipping - // TODO: move to a separate class - // TODO: check current customer can apply operations on specified cart + if (!$shippingMethod['shipping_carrier_code']) { // FIXME: check the E_WARNING here + throw new GraphQlInputException(__('Required parameter "shipping_carrier_code" is missing')); } - $quoteId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); - $quote = $this->cartRepository->get($quoteId); // TODO: catch no such entity exception - $this->setShippingMethods($shippingMethods, $quote); + if (!$shippingMethod['shipping_method_code']) { // FIXME: check the E_WARNING here + throw new GraphQlInputException(__('Required parameter "shipping_method_code" is missing')); + } - $quote->collectTotals(); - $quote->save(); - //$this->cartRepository->save($quote); + try { + $cartId = $this->maskedQuoteIdToQuoteId->execute((string) $maskedCartId); + } catch (NoSuchEntityException $exception) { + throw new GraphQlNoSuchEntityException( + __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $maskedCartId]) + ); + } - return 'Success!'; - } + if (false === $this->isCartMutationAllowedForCurrentUser->execute($cartId)) { + throw new GraphQlAuthorizationException( + __( + 'The current user cannot perform operations on cart "%masked_cart_id"', + ['masked_cart_id' => $maskedCartId] + ) + ); + } - private function setShippingMethods($shippingMethods, CartInterface $quote) - { - $addresses = $quote->getAllShippingAddresses(); - /** @var \Magento\Quote\Model\Quote\Address $address */ - foreach ($addresses as $address) { - $addressId = $address->getId(); - $shippingMethodForAddress = array_search($addressId, array_column($shippingMethods, 'cart_address_id')); - if ($shippingMethodForAddress !== false) { - $address->setShippingMethod($shippingMethods[$shippingMethodForAddress]['shipping_method_code']); -// $address->setCollectShippingRates(1); - $address->save(); - } + try { + $this->shippingMethodManagement->set( + $cartId, + $shippingMethods['shipping_carrier_code'], + $shippingMethods['shipping_method_code'] + ); + } catch (InputException $exception) { + throw new GraphQlInputException(__($exception->getMessage())); + } catch (CouldNotSaveException $exception) { + throw new GraphQlInputException(__($exception->getMessage())); + } catch (StateException $exception) { + throw new GraphQlInputException(__($exception->getMessage())); + } catch (NoSuchEntityException $exception) { + throw new GraphQlNoSuchEntityException(__($exception->getMessage())); } - // TODO: make sure that shipping method is assigned for all addresses + + return 'Success!'; // TODO we should return cart here } } \ No newline at end of file diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 8ecb340db691b..45f98daeaed06 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -53,7 +53,8 @@ input SetShippingMethodsOnCartInput { } input ShippingMethodForAddressInput { - cart_address_id: String! # todo: int? + cart_address_id: int + shipping_carrier_code: String! shipping_method_code: String! } @@ -66,7 +67,7 @@ type SetShippingAddressesOnCartOutput { } type SetShippingMethodsOnCartOutput { - cart: String + cart: String #TODO: temp placeholder, should be Cart! } # If no address is provided, the system get address assigned to a quote From 6c7ce718ea5d2cc91269242963bda2293388f00e Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Thu, 4 Oct 2018 11:56:26 +0300 Subject: [PATCH 0141/1158] MAGETWO-93769: Catalog performance improvements --- .../Catalog/Model/ProductIdLocator.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductIdLocator.php b/app/code/Magento/Catalog/Model/ProductIdLocator.php index ba8fa01b40f58..21ddf06427982 100644 --- a/app/code/Magento/Catalog/Model/ProductIdLocator.php +++ b/app/code/Magento/Catalog/Model/ProductIdLocator.php @@ -38,23 +38,28 @@ class ProductIdLocator implements \Magento\Catalog\Model\ProductIdLocatorInterfa private $idsBySku = []; /** - * Page size to iterate collection + * Batch size to iterate collection + * + * @var int */ - private $pageSize = 10000; + private $batchSize; /** * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory - * @param string $limitIdsBySkuValues + * @param string $idsLimit + * @param int $batchSize [optional] */ public function __construct( \Magento\Framework\EntityManager\MetadataPool $metadataPool, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory, - $idsLimit + $idsLimit, + $batchSize = 5000 ) { $this->metadataPool = $metadataPool; $this->collectionFactory = $collectionFactory; $this->idsLimit = (int)$idsLimit; + $this->batchSize = $batchSize; } /** @@ -77,12 +82,14 @@ public function retrieveProductIdsBySkus(array $skus) $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) ->getLinkField(); - $collection->setPageSize($this->pageSize); + $collection->setPageSize($this->batchSize); $pages = $collection->getLastPageNumber(); for ($currentPage = 1; $currentPage <= $pages; $currentPage++) { $collection->setCurPage($currentPage); foreach ($collection->getItems() as $item) { - $this->idsBySku[strtolower(trim($item->getSku()))][$item->getData($linkField)] = $item->getTypeId(); + $sku = strtolower(trim($item->getSku())); + $itemIdentifier = $item->getData($linkField); + $this->idsBySku[$sku][$itemIdentifier] = $item->getTypeId(); } $collection->clear(); } From ce0cb8c76c31545d3527243cbef1bd77947caf49 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Thu, 4 Oct 2018 13:39:59 +0300 Subject: [PATCH 0142/1158] MAGETWO-67269: Gift Options set to no still show up as choices on front end order page - Fix statics. --- app/code/Magento/GiftMessage/Block/Message/Inline.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/GiftMessage/Block/Message/Inline.php b/app/code/Magento/GiftMessage/Block/Message/Inline.php index f44f967cefdc6..4a9311c1b4ba2 100644 --- a/app/code/Magento/GiftMessage/Block/Message/Inline.php +++ b/app/code/Magento/GiftMessage/Block/Message/Inline.php @@ -139,7 +139,7 @@ public function getType() /** * Define checkout type * - * @param $type string + * @param string $type * @return $this * @codeCoverageIgnore */ @@ -278,6 +278,8 @@ public function countItems() } /** + * Call method getItemsHasMessages + * * @deprecated Misspelled method * @see getItemsHasMessages */ From bdf8c0d5632bf05ce6be5a6f084dba46918a2297 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Thu, 4 Oct 2018 14:22:38 +0300 Subject: [PATCH 0143/1158] MAGETWO-93769: Catalog performance improvements --- app/code/Magento/Catalog/Model/ProductIdLocator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductIdLocator.php b/app/code/Magento/Catalog/Model/ProductIdLocator.php index 21ddf06427982..e51deb7f6cbe7 100644 --- a/app/code/Magento/Catalog/Model/ProductIdLocator.php +++ b/app/code/Magento/Catalog/Model/ProductIdLocator.php @@ -48,13 +48,13 @@ class ProductIdLocator implements \Magento\Catalog\Model\ProductIdLocatorInterfa * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory * @param string $idsLimit - * @param int $batchSize [optional] + * @param int $batchSize defines how many items can be processed by one request */ public function __construct( \Magento\Framework\EntityManager\MetadataPool $metadataPool, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory, $idsLimit, - $batchSize = 5000 + int $batchSize = 5000 ) { $this->metadataPool = $metadataPool; $this->collectionFactory = $collectionFactory; From ef8f126056b004cea86c5ce726794844e969f848 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Thu, 4 Oct 2018 15:15:11 +0300 Subject: [PATCH 0144/1158] graph-ql: concept of shipping address coverage, added separate flows for multi shipping and single shipping --- .../MultiShipping.php | 23 ++++ .../SingleShipping.php | 63 ++++++++++ .../SetShippingAddressesOnCart.php | 109 ++++++++++++------ 3 files changed, 162 insertions(+), 33 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php new file mode 100644 index 0000000000000..71560a26c03ee --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php @@ -0,0 +1,23 @@ +<?php +/** + * @author Atwix Team + * @copyright Copyright (c) 2018 Atwix (https://www.atwix.com/) + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart; + +class MultiShipping +{ + /** + * @param int $cartId + * @param array $cartItems + * @param int|null $customerAddressId + * @param array|null $address + * @return void + */ + public function setAddress(int $cartId, array $cartItems, ?int $customerAddressId, ?array $address): void + { + //TODO: implement multi shipping + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php new file mode 100644 index 0000000000000..536a907541b1a --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php @@ -0,0 +1,63 @@ +<?php +/** + * @author Atwix Team + * @copyright Copyright (c) 2018 Atwix (https://www.atwix.com/) + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart; + +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\ShippingAddressManagementInterface; +use Magento\Customer\Api\AddressRepositoryInterface; + +class SingleShipping +{ + /** + * @var ShippingAddressManagementInterface + */ + private $shippingAddressManagement; + + /** + * @var AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @var Address + */ + private $addressModel; + + /** + * @param ShippingAddressManagementInterface $shippingAddressManagement + * @param AddressRepositoryInterface $addressRepository + * @param Address $addressModel + */ + public function __construct( + ShippingAddressManagementInterface $shippingAddressManagement, + AddressRepositoryInterface $addressRepository, + Address $addressModel + ) { + $this->shippingAddressManagement = $shippingAddressManagement; + $this->addressRepository = $addressRepository; + $this->addressModel = $addressModel; + } + + /** + * @param int $cartId + * @param int|null $customerAddressId + * @param array|null $address + * @return void + */ + public function setAddress(int $cartId, ?int $customerAddressId, ?array $address): void + { + if($customerAddressId) { + $customerAddress = $this->addressRepository->getById($customerAddressId); + $shippingAddress = $this->addressModel->importCustomerAddressData($customerAddress); + } else { + $shippingAddress = $this->addressModel->addData($address); + } + + $this->shippingAddressManagement->assign($cartId, $shippingAddress); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php index 9d54792136367..f3960f66d2792 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php @@ -7,15 +7,15 @@ namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress; -use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; -use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\ShippingAddressManagementInterface; +use Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\MultiShipping; +use Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\SingleShipping; /** * @inheritdoc @@ -23,48 +23,49 @@ class SetShippingAddressesOnCart implements ResolverInterface { /** - * @var ShippingAddressManagementInterface + * @var DataObjectHelper */ - private $shippingAddressManagement; + private $dataObjectHelper; /** - * @var AddressRepositoryInterface + * @var MaskedQuoteIdToQuoteIdInterface */ - private $addressRepository; + private $maskedQuoteIdToQuoteId; /** - * @var Address + * @var MultiShipping */ - private $addressModel; + private $multiShipping; + /** - * @var DataObjectHelper + * @var SingleShipping */ - private $dataObjectHelper; + private $singleShipping; /** - * @var MaskedQuoteIdToQuoteIdInterface + * @var ShippingAddressManagementInterface */ - private $maskedQuoteIdToQuoteId; + private $shippingAddressManagement; /** - * @param ShippingAddressManagementInterface $shippingAddressManagement - * @param AddressRepositoryInterface $addressRepository - * @param Address $addressModel * @param DataObjectHelper $dataObjectHelper * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + * @param MultiShipping $multiShipping + * @param SingleShipping $singleShipping + * @param ShippingAddressManagementInterface $shippingAddressManagement */ public function __construct( - ShippingAddressManagementInterface $shippingAddressManagement, - AddressRepositoryInterface $addressRepository, - Address $addressModel, DataObjectHelper $dataObjectHelper, - MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, + MultiShipping $multiShipping, + SingleShipping $singleShipping, + ShippingAddressManagementInterface $shippingAddressManagement ) { - $this->shippingAddressManagement = $shippingAddressManagement; - $this->addressRepository = $addressRepository; - $this->addressModel = $addressModel; $this->dataObjectHelper = $dataObjectHelper; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->multiShipping = $multiShipping; + $this->singleShipping = $singleShipping; + $this->shippingAddressManagement = $shippingAddressManagement; } /** @@ -78,7 +79,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $maskedCartId = $args['input']['cart_id']; $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); - $customerAddressId = $args['input']['customer_address_id'] ?? 0; + $customerAddressId = $args['input']['customer_address_id'] ?? null; $address = $args['input']['address'] ?? null; $cartItems = $args['input']['cart_items'] ?? []; @@ -86,19 +87,61 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value throw new GraphQlInputException(__('Query should contain either address id or address input.')); } + //TODO: how to determine whether is multi shipping or not if (!$cartItems) { - if($customerAddressId) { - $customerAddress = $this->addressRepository->getById($customerAddressId); - $shippingAddress = $this->addressModel->importCustomerAddressData($customerAddress); - $this->shippingAddressManagement->assign($cartId, $shippingAddress); - } else { - $shippingAddress = $this->addressModel->addData($address); - $this->shippingAddressManagement->assign($cartId, $shippingAddress); - } + //TODO: assign cart items + $this->singleShipping->setAddress($cartId, $customerAddressId, $address); } else { - //TODO: implement multi shipping address assign flow + $this->multiShipping->setAddress($cartId, $cartItems, $customerAddressId, $address); } - return []; + //TODO: implement Cart object in the separate resolver + $shippingAddress = $this->shippingAddressManagement->get($cartId); + return [ + 'cart' => [ + 'applied_coupon' => [ + 'code' => '' + ], + 'addresses' => [[ + 'firstname' => $shippingAddress->getFirstname(), + 'lastname' => $shippingAddress->getLastname(), + 'company' => $shippingAddress->getCompany(), + 'street' => $shippingAddress->getStreet(), + 'city' => $shippingAddress->getCity(), + 'region' => [ + 'code' => $shippingAddress->getRegionCode(), + 'label' => $shippingAddress->getRegion() + ], + 'country' => [ + 'code' => $shippingAddress->getCountryId(), + 'label' => '' + ], + 'postcode' => $shippingAddress->getPostcode(), + 'telephone' => $shippingAddress->getTelephone(), + 'address_type' => 'SHIPPING', + 'selected_shipping_method' => [ + 'code' => 'test', + 'label' => 'test', + 'free_shipping' => 'test', + 'error_message' => 'test' + ], + 'available_shipping_methods' => [[ + 'code' => 'test', + 'label' => 'test', + 'free_shipping' => 'test', + 'error_message' => 'test' + ]], + 'items_weight' => [0], + 'customer_notes' => $shippingAddress->getLastname(), + 'cart_items' => [[ + 'cart_item_id' => '', + 'quantity' => 0 + ]], + 'applied_coupon' => [ + 'code' => '' + ] + ]] + ] + ]; } } From e7c2ddcfbfa9668c0a7d8c8706892740add84c5d Mon Sep 17 00:00:00 2001 From: Yurii Borysov <yurii_borysov@epam.com> Date: Thu, 4 Oct 2018 16:12:11 +0300 Subject: [PATCH 0145/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix elements arrangement issue --- .../adminhtml/web/css/grouped-product.css | 13 +++++-- .../adminhtml/web/js/grouped-product-grid.js | 34 +++++++++++++------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css b/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css index cd0aa25ae1f88..9142eaf90899e 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css @@ -67,9 +67,8 @@ text-overflow: ellipsis; } - .position { - width:90px; + width: 100px; } .icon-rearrange-position > span { @@ -91,6 +90,11 @@ speak: none; } +.position > * { + float: left; + margin: 3px; +} + .position-widget-input { text-align: center; width: 40px; @@ -103,3 +107,8 @@ .icon-backward:before { content: '\e619'; } + +.icon-rearrange-position, .icon-rearrange-position:hover { + color: #d9d9d9; + text-decoration: none; +} diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 7c9563bb1a0ce..c1a35cb0afede 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -36,7 +36,17 @@ define([ * @param position */ shiftNextPagesPositions: function (position) { - console.log("todo: shifting positions to right on next pages related data"); + var recordData = this.recordData(); + if (~~this.currentPage() === this.pages()) { + return false; + } else { + var startIndex = ~~this.currentPage() * this.pageSize, + offset = position - startIndex + 1; + for (var index = startIndex; index < recordData.length; index++) { + recordData[index].position = index + offset; + } + this.recordData(recordData); + } }, @@ -47,30 +57,36 @@ define([ * @param event */ updateGridPosition: function (data, event) { - var inputValue = ~~event.target.value, + var inputValue = parseInt(event.target.value), recordData = this.recordData(), record, + previousValue, updatedRecord; record = this.elems().find(function (obj) { return obj.dataScope === data.parentScope - }).data(); + }); - if (inputValue === ~~record.positionCalculated) { + previousValue = this.getCalculatedPosition(record); + + if (isNaN(inputValue) || inputValue < 0 || inputValue === previousValue) { return false; } this.elems([]); - updatedRecord = this.getUpdatedRecordIndex(recordData, record.id); + updatedRecord = this.getUpdatedRecordIndex(recordData, record.data().id); if (inputValue >= this.recordData().size() - 1) { recordData[updatedRecord].position = this.getGlobalMaxPosition() + 1; } else { - recordData[updatedRecord].position = inputValue; recordData.forEach(function (value, index) { - if (~~value.id !== ~~record.id) { - recordData[index].position = (index !== inputValue) ? index : index + 1; + if (~~value.id === ~~record.data().id) { + recordData[index].position = inputValue; + } else if (inputValue > previousValue && index <= inputValue) { + recordData[index].position = index - 1; + } else if (inputValue < previousValue && index >= inputValue) { + recordData[index].position = index + 1; } }); } @@ -203,7 +219,5 @@ define([ return ~~r.position })); } - - }); }); From ae03f80da3b6500cf245f06133f528257490852d Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 4 Oct 2018 16:50:28 +0300 Subject: [PATCH 0146/1158] MAGETWO-95332: Update price in shopping cart after product save --- .../StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml index 91f9cbf398d24..b4747a6bf7273 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUpdatePriceInShoppingCartAfterProductSaveTest.xml @@ -30,6 +30,7 @@ <after> <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> <actionGroup ref="SetCustomerDataLifetimeActionGroup" stepKey="setDefaultCustomerDataLifetime"/> + <magentoCLI command="indexer:reindex customer_grid" stepKey="reindexCustomerGrid"/> <actionGroup ref="logout" stepKey="logout"/> </after> <!--Go to product page--> From b0bc510b885067a725ecce2339f614327528797d Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Thu, 4 Oct 2018 17:21:05 +0300 Subject: [PATCH 0147/1158] MAGETWO-93769: Catalog performance improvements --- .../Catalog/Model/ProductIdLocator.php | 4 +-- .../Product/Price/TierPriceStorageTest.php | 24 ++++++++++++++++++ .../Test/Unit/Model/ProductIdLocatorTest.php | 17 +++++++++++-- .../ResourceModel/Product/CollectionTest.php | 25 +++++++++++++++++-- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductIdLocator.php b/app/code/Magento/Catalog/Model/ProductIdLocator.php index e51deb7f6cbe7..4c4e6b416527b 100644 --- a/app/code/Magento/Catalog/Model/ProductIdLocator.php +++ b/app/code/Magento/Catalog/Model/ProductIdLocator.php @@ -48,7 +48,7 @@ class ProductIdLocator implements \Magento\Catalog\Model\ProductIdLocatorInterfa * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory * @param string $idsLimit - * @param int $batchSize defines how many items can be processed by one request + * @param int $batchSize defines how many items can be processed by one iteration */ public function __construct( \Magento\Framework\EntityManager\MetadataPool $metadataPool, @@ -86,7 +86,7 @@ public function retrieveProductIdsBySkus(array $skus) $pages = $collection->getLastPageNumber(); for ($currentPage = 1; $currentPage <= $pages; $currentPage++) { $collection->setCurPage($currentPage); - foreach ($collection->getItems() as $item) { + foreach ($collection->getIterator() as $item) { $sku = strtolower(trim($item->getSku())); $itemIdentifier = $item->getData($linkField); $this->idsBySku[$sku][$itemIdentifier] = $item->getTypeId(); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php index c9288790ed6e1..a97f2281125a6 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php @@ -152,6 +152,30 @@ public function testGet() $this->assertEquals(2, count($prices)); } + /** + * Test get method without tierprices. + * + * @return void + */ + public function testGetWithoutTierPrices() + { + $skus = ['simple', 'virtual']; + $this->tierPriceValidator + ->expects($this->once()) + ->method('validateSkus') + ->with($skus) + ->willReturn($skus); + $this->productIdLocator->expects($this->atLeastOnce()) + ->method('retrieveProductIdsBySkus') + ->with(['simple', 'virtual']) + ->willReturn(['simple' => ['2' => 'simple'], 'virtual' => ['3' => 'virtual']]); + $this->tierPricePersistence->expects($this->once())->method('get')->willReturn([]); + $this->tierPricePersistence->expects($this->never())->method('getEntityLinkField'); + $this->tierPriceFactory->expects($this->never())->method('create'); + $prices = $this->tierPriceStorage->get($skus); + $this->assertEmpty($prices); + } + /** * Test update method. * diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php index b730e12ca820b..6455aa58dd234 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php @@ -58,7 +58,16 @@ public function testRetrieveProductIdsBySkus() { $skus = ['sku_1', 'sku_2']; $collection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class) - ->setMethods(['getIterator', 'addFieldToFilter']) + ->setMethods( + [ + 'getIterator', + 'addFieldToFilter', + 'setPageSize', + 'getLastPageNumber', + 'setCurPage', + 'clear' + ] + ) ->disableOriginalConstructor()->getMock(); $product = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) ->setMethods(['getSku', 'getData', 'getTypeId']) @@ -69,7 +78,11 @@ public function testRetrieveProductIdsBySkus() $this->collectionFactory->expects($this->once())->method('create')->willReturn($collection); $collection->expects($this->once())->method('addFieldToFilter') ->with(\Magento\Catalog\Api\Data\ProductInterface::SKU, ['in' => $skus])->willReturnSelf(); - $collection->expects($this->once())->method('getIterator')->willReturn(new \ArrayIterator([$product])); + $collection->expects($this->atLeastOnce())->method('getIterator')->willReturn(new \ArrayIterator([$product])); + $collection->expects($this->atLeastOnce())->method('setPageSize')->willReturnSelf(); + $collection->expects($this->atLeastOnce())->method('getLastPageNumber')->willReturn(1); + $collection->expects($this->atLeastOnce())->method('setCurPage')->with(1)->willReturnSelf(); + $collection->expects($this->atLeastOnce())->method('clear')->willReturnSelf(); $this->metadataPool ->expects($this->once()) ->method('getMetadata') diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php index dbbb3fb29513b..bb39aa7f9db77 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php @@ -58,13 +58,18 @@ class CollectionTest extends \PHPUnit\Framework\TestCase */ private $storeManager; + /** + * @var \Magento\Framework\Data\Collection\EntityFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $entityFactory; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $entityFactory = $this->createMock(\Magento\Framework\Data\Collection\EntityFactory::class); + $this->entityFactory = $this->createMock(\Magento\Framework\Data\Collection\EntityFactory::class); $logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); @@ -168,7 +173,7 @@ protected function setUp() $this->collection = $this->objectManager->getObject( \Magento\Catalog\Model\ResourceModel\Product\Collection::class, [ - 'entityFactory' => $entityFactory, + 'entityFactory' => $this->entityFactory, 'logger' => $logger, 'fetchStrategy' => $fetchStrategy, 'eventManager' => $eventManager, @@ -379,4 +384,20 @@ public function testAddTierPriceData() $this->assertSame($this->collection, $this->collection->addTierPriceData()); } + + /** + * Test for getNewEmptyItem() method + * + * @return void + */ + public function testGetNewEmptyItem() + { + $item = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + $this->entityFactory->expects($this->once())->method('create')->willReturn($item); + $firstItem = $this->collection->getNewEmptyItem(); + $secondItem = $this->collection->getNewEmptyItem(); + $this->assertEquals($firstItem, $secondItem); + } } From 929ed778dd4f6157d2ddfbc49289661559d384eb Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Thu, 4 Oct 2018 18:07:35 +0300 Subject: [PATCH 0148/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Magento/Backend/Block/Media/Uploader.php | 6 +++--- .../adminhtml/templates/media/uploader.phtml | 2 +- .../view/adminhtml/web/js/media-uploader.js | 18 ++++++++++-------- .../templates/browser/content/uploader.phtml | 15 ++++++++++----- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php index 1995d72661e2e..22e9197418e4c 100644 --- a/app/code/Magento/Backend/Block/Media/Uploader.php +++ b/app/code/Magento/Backend/Block/Media/Uploader.php @@ -130,11 +130,11 @@ public function getImageUploadMaxHeight() /** * Get image resize configuration * - * @return bool + * @return int */ - public function getIsResizeEnabled(): bool + public function getIsResizeEnabled(): int { - return $this->imageUploadConfig->isResizeEnabled(); + return (int)$this->imageUploadConfig->isResizeEnabled(); } /** diff --git a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml index edd54ae38b6a1..d6e97cf4d58e3 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml @@ -13,7 +13,7 @@ data-mage-init='{ "Magento_Backend/js/media-uploader" : { "maxFileSize": <?= /* @escapeNotVerified */ $block->getFileSizeService()->getMaxFileSize() ?>, - "maxWidth":<?= /* @escapeNotVerified */ $block->getImageUploadMaxWidth() ?> , + "maxWidth": <?= /* @escapeNotVerified */ $block->getImageUploadMaxWidth() ?>, "maxHeight": <?= /* @escapeNotVerified */ $block->getImageUploadMaxHeight() ?>, "isResizeEnabled": <?= /* @noEscape */ $block->getIsResizeEnabled() ?> } diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js index 35e9ec244df24..2a15f5262bda1 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js @@ -36,10 +36,17 @@ define([ var self = this, progressTmpl = mageTemplate('[data-template="uploader"]'), - resizeConfig = { - action: 'resize' + isResizeEnabled = this.options.isResizeEnabled, + resizeConfiguration = { + action: 'resize', + maxWidth: this.options.maxWidth, + maxHeight: this.options.maxHeight }; + if (isResizeEnabled === 0) { + resizeConfiguration = {action: 'resize'}; + } + this.element.find('input[type=file]').fileupload({ dataType: 'json', formData: { @@ -123,18 +130,13 @@ define([ stop: fileUploader.uploaderConfig.stop }); - if (typeof this.options.isResizeEnabled !== 'undefined' && this.options.isResizeEnabled === true) { - resizeConfig.maxWidth = this.options.maxWidth; - resizeConfig.maxHeight = this.options.maxHeight; - } - this.element.find('input[type=file]').fileupload('option', { process: [{ action: 'load', fileTypes: /^image\/(gif|jpeg|png)$/, maxFileSize: this.options.maxFileSize }, - resizeConfig, + resizeConfiguration, { action: 'save' }] diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml index 5f4e40667eda5..b1824f639c940 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml @@ -17,6 +17,13 @@ foreach ($filters as $media_type) { }, $media_type['files'])); } +$resizeConfig = ($block->getIsResizeEnabled()) + ? "{action: 'resize', maxWidth: " + . $block->getImageUploadMaxWidth() + . ", maxHeight: " + . $block->getImageUploadMaxHeight() + . "}" + : "{action: 'resize'}"; ?> <div id="<?= $block->getHtmlId() ?>" class="uploader"> @@ -145,11 +152,9 @@ require([ action: 'load', fileTypes: /^image\/(gif|jpeg|png)$/, maxFileSize: <?= (int) $block->getFileSizeService()->getMaxFileSize() ?> * 10 - }, { - action: 'resize', - maxWidth: <?= /* @escapeNotVerified */ $block->getImageUploadMaxWidth() ?> , - maxHeight: <?= /* @escapeNotVerified */ $block->getImageUploadMaxHeight() ?> - }, { + }, + <?= /* @noEscape*/ $resizeConfig ?>, + { action: 'save' }] }); From 3bd78c6897fdccf6deb351b4b3510e979bb673a6 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Thu, 4 Oct 2018 20:42:45 +0300 Subject: [PATCH 0149/1158] MAGETWO-91650: Translation not working for product alerts - Add foreign key for store table --- app/code/Magento/ProductAlert/etc/db_schema.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ProductAlert/etc/db_schema.xml b/app/code/Magento/ProductAlert/etc/db_schema.xml index 1d145482ea38f..2b3d9c0db3bc5 100644 --- a/app/code/Magento/ProductAlert/etc/db_schema.xml +++ b/app/code/Magento/ProductAlert/etc/db_schema.xml @@ -41,7 +41,7 @@ table="product_alert_price" column="website_id" referenceTable="store_website" referenceColumn="website_id" onDelete="CASCADE"/> <constraint xsi:type="foreign" name="PRODUCT_ALERT_PRICE_STORE_ID_STORE_STORE_ID" - table="product_alert_stock" column="website_id" referenceTable="store" + table="product_alert_stock" column="store_id" referenceTable="store" referenceColumn="store_id" onDelete="CASCADE"/> <index name="PRODUCT_ALERT_PRICE_CUSTOMER_ID" indexType="btree"> <column name="customer_id"/> @@ -82,7 +82,7 @@ table="product_alert_stock" column="website_id" referenceTable="store_website" referenceColumn="website_id" onDelete="CASCADE"/> <constraint xsi:type="foreign" name="PRODUCT_ALERT_STOCK_STORE_ID_STORE_STORE_ID" - table="product_alert_stock" column="website_id" referenceTable="store" + table="product_alert_stock" column="store_id" referenceTable="store" referenceColumn="store_id" onDelete="CASCADE"/> <constraint xsi:type="foreign" name="PRODUCT_ALERT_STOCK_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID" table="product_alert_stock" column="customer_id" referenceTable="customer_entity" From 9dc3345ae68c6a90d1a19d58d0ec29bc07d15198 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Thu, 4 Oct 2018 22:20:21 +0300 Subject: [PATCH 0150/1158] Fix pr --- .../DataProvider/NotificationDataProvider.php | 84 ++-------- .../Magento/Sales/Model/Order/Address.php | 153 +++--------------- .../Sales/Model/Order/Payment/Transaction.php | 39 +---- app/code/Magento/Store/Model/Store.php | 9 +- 4 files changed, 50 insertions(+), 235 deletions(-) diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 26e698b67545b..8418b4f9a753d 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -82,9 +82,7 @@ public function __construct( } /** - * Get data - * - * @return mixed + * @inheritdoc */ public function getData() { @@ -97,10 +95,7 @@ public function getData() } /** - * Get Meta - * - * @return array - * @throws \Magento\Framework\Exception\LocalizedException + * @inheritdoc */ public function getMeta() { @@ -112,9 +107,7 @@ public function getMeta() } /** - * Get Data Provider name - * - * @return string + * @inheritdoc */ public function getName() { @@ -122,9 +115,7 @@ public function getName() } /** - * Get config data - * - * @return mixed + * @inheritdoc */ public function getConfigData() { @@ -132,11 +123,7 @@ public function getConfigData() } /** - * Set config data - * - * @param mixed $config - * - * @return bool + * @inheritdoc */ public function setConfigData($config) { @@ -146,13 +133,7 @@ public function setConfigData($config) } /** - * Get Field Meta Info - * - * @param string $fieldSetName - * @param string $fieldName - * - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function getFieldMetaInfo($fieldSetName, $fieldName) { @@ -160,12 +141,7 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) } /** - * Get Field Set Meta Info - * - * @param string $fieldSetName - * - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function getFieldSetMetaInfo($fieldSetName) { @@ -173,12 +149,7 @@ public function getFieldSetMetaInfo($fieldSetName) } /** - * Get Fields Meta Info - * - * @param string $fieldSetName - * - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function getFieldsMetaInfo($fieldSetName) { @@ -186,9 +157,7 @@ public function getFieldsMetaInfo($fieldSetName) } /** - * Get Primary Field Name - * - * @return string + * @inheritdoc */ public function getPrimaryFieldName() { @@ -196,9 +165,7 @@ public function getPrimaryFieldName() } /** - * Get Request Field Name - * - * @return string + * @inheritdoc */ public function getRequestFieldName() { @@ -206,47 +173,28 @@ public function getRequestFieldName() } /** - * Add Filter - * - * @param \Magento\Framework\Api\Filter $filter - * - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function addFilter(\Magento\Framework\Api\Filter $filter) { } /** - * Add Order - * - * @param string $field - * @param string $direction - * - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function addOrder($field, $direction) { } /** - * Set Limit - * - * @param int $offset - * @param int $size - * - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function setLimit($offset, $size) { } /** - * Get Search Criteria - * - * @return SearchCriteriaInterface + * @inheritdoc */ public function getSearchCriteria() { @@ -254,9 +202,7 @@ public function getSearchCriteria() } /** - * Get Search Result - * - * @return SearchResultInterface + * @inheritdoc */ public function getSearchResult() { diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index 98433899cca26..a19c587216b1c 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -516,11 +516,7 @@ public function setParentId($id) } /** - * Sets the country address ID for the order address. - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCustomerAddressId($id) { @@ -528,11 +524,7 @@ public function setCustomerAddressId($id) } /** - * Sets the region ID for the order address. - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setRegionId($id) { @@ -540,11 +532,7 @@ public function setRegionId($id) } /** - * Sets the street values, if any, for the order address. - * - * @param string|string[] $street - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setStreet($street) { @@ -552,11 +540,7 @@ public function setStreet($street) } /** - * Sets the customer ID for the order address. - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCustomerId($id) { @@ -564,11 +548,7 @@ public function setCustomerId($id) } /** - * Sets the fax number for the order address. - * - * @param string $fax - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setFax($fax) { @@ -576,11 +556,7 @@ public function setFax($fax) } /** - * Sets the region for the order address. - * - * @param string $region - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setRegion($region) { @@ -588,11 +564,7 @@ public function setRegion($region) } /** - * Sets the postal code for the order address. - * - * @param string $postcode - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setPostcode($postcode) { @@ -600,11 +572,7 @@ public function setPostcode($postcode) } /** - * Sets the last name for the order address. - * - * @param string $lastname - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setLastname($lastname) { @@ -612,11 +580,7 @@ public function setLastname($lastname) } /** - * Sets the city for the order address. - * - * @param string $city - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCity($city) { @@ -624,11 +588,7 @@ public function setCity($city) } /** - * Sets the email address for the order address. - * - * @param string $email - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setEmail($email) { @@ -636,11 +596,7 @@ public function setEmail($email) } /** - * Sets the telephone number for the order address. - * - * @param string $telephone - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setTelephone($telephone) { @@ -648,11 +604,7 @@ public function setTelephone($telephone) } /** - * Sets the country ID for the order address. - * - * @param string $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCountryId($id) { @@ -660,11 +612,7 @@ public function setCountryId($id) } /** - * Sets the first name for the order address. - * - * @param string $firstname - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setFirstname($firstname) { @@ -672,11 +620,7 @@ public function setFirstname($firstname) } /** - * Sets the address type for the order address. - * - * @param string $addressType - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setAddressType($addressType) { @@ -684,11 +628,7 @@ public function setAddressType($addressType) } /** - * Sets the prefix for the order address. - * - * @param string $prefix - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setPrefix($prefix) { @@ -696,11 +636,7 @@ public function setPrefix($prefix) } /** - * Sets the middle name for the order address. - * - * @param string $middlename - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setMiddlename($middlename) { @@ -708,11 +644,7 @@ public function setMiddlename($middlename) } /** - * Sets the suffix for the order address. - * - * @param string $suffix - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setSuffix($suffix) { @@ -720,11 +652,7 @@ public function setSuffix($suffix) } /** - * Sets the company for the order address. - * - * @param string $company - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCompany($company) { @@ -732,11 +660,7 @@ public function setCompany($company) } /** - * Sets the VAT ID for the order address. - * - * @param string $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatId($id) { @@ -744,11 +668,7 @@ public function setVatId($id) } /** - * Sets the VAT-is-valid flag value for the order address. - * - * @param int $vatIsValid - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatIsValid($vatIsValid) { @@ -756,11 +676,7 @@ public function setVatIsValid($vatIsValid) } /** - * Sets the VAT request ID for the order address. - * - * @param string $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatRequestId($id) { @@ -768,11 +684,7 @@ public function setVatRequestId($id) } /** - * Set region code - * - * @param string $regionCode - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setRegionCode($regionCode) { @@ -780,11 +692,7 @@ public function setRegionCode($regionCode) } /** - * Sets the VAT request date for the order address. - * - * @param string $vatRequestDate - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatRequestDate($vatRequestDate) { @@ -792,11 +700,7 @@ public function setVatRequestDate($vatRequestDate) } /** - * Sets the VAT-request-success flag value for the order address. - * - * @param int $vatRequestSuccess - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatRequestSuccess($vatRequestSuccess) { @@ -804,9 +708,7 @@ public function setVatRequestSuccess($vatRequestSuccess) } /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Sales\Api\Data\OrderAddressExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -814,10 +716,7 @@ public function getExtensionAttributes() } /** - * Set an extension attributes object. - * - * @param \Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 8f9f275de1658..69e79d71db98b 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -942,11 +942,7 @@ public function getCreatedAt() } /** - * Gets an array of child transactions for the transaction. - * - * @param string $createdAt - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setCreatedAt($createdAt) { @@ -954,11 +950,7 @@ public function setCreatedAt($createdAt) } /** - * Sets the parent ID for the transaction. - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setParentId($id) { @@ -966,11 +958,7 @@ public function setParentId($id) } /** - * Sets the order ID for the transaction. - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setOrderId($id) { @@ -978,11 +966,7 @@ public function setOrderId($id) } /** - * Sets the payment ID for the transaction. - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setPaymentId($id) { @@ -990,11 +974,7 @@ public function setPaymentId($id) } /** - * Sets the value of the is-closed flag for the transaction. - * - * @param int $isClosed - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setIsClosed($isClosed) { @@ -1002,9 +982,7 @@ public function setIsClosed($isClosed) } /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Sales\Api\Data\TransactionExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -1012,10 +990,7 @@ public function getExtensionAttributes() } /** - * Set an extension attributes object. - * - * @param \Magento\Sales\Api\Data\TransactionExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Sales\Api\Data\TransactionExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index c212ebfec845f..ab9b356e7a748 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1386,10 +1386,7 @@ public function getScopeType() } /** - * Get Scope Type Name - * - * @return string - * @since 100.1.0 + * @inheritdoc */ public function getScopeTypeName() { @@ -1397,9 +1394,7 @@ public function getScopeTypeName() } /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Store\Api\Data\StoreExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { From e140d29a3e6ec297be4e8fffdfea07bbc521b971 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 4 Oct 2018 14:57:27 -0500 Subject: [PATCH 0151/1158] MAGETWO-89232: Validation error appears if duplicate product twice --- .../Model/Exception/UrlAlreadyExistsException.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php b/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php index c7e83819f2569..fdfadc5737af2 100644 --- a/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php +++ b/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php @@ -8,10 +8,12 @@ use Magento\Framework\Phrase; /** + * Exception for already created url. + * * @api * @since 100.2.0 */ -class UrlAlreadyExistsException extends \Magento\Framework\Exception\LocalizedException +class UrlAlreadyExistsException extends \Magento\Framework\Exception\AlreadyExistsException { /** * @var array @@ -34,6 +36,8 @@ public function __construct(Phrase $phrase = null, \Exception $cause = null, $co } /** + * Returns urls. + * * @return array * @since 100.2.0 */ From 78e8059da0e05ccdacc0c5b8777dbfa10794e3ed Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Fri, 5 Oct 2018 11:47:10 +0300 Subject: [PATCH 0152/1158] MAGETWO-91657: Advanced pricing the bulk discounts by percentage returns error when set - Fixed PhpDoc; --- .../Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php index 1f0da62f61056..a529580e29239 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php @@ -54,7 +54,7 @@ public function modifyData(array $data) } /** - * Add tier price info to meta array. {@inheritdoc} + * Add tier price info to meta array. * * @since 101.1.0 * @param array $meta From 3a65d73ff8b2cc5d801de99f182389a52edec318 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Fri, 5 Oct 2018 11:52:38 +0300 Subject: [PATCH 0153/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Magento/Catalog/etc/adminhtml/system.xml | 17 +++++++++++++++++ app/code/Magento/Catalog/etc/config.xml | 3 +++ 2 files changed, 20 insertions(+) diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index 71a799fd22427..26da542cde65b 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -10,6 +10,9 @@ <tab id="catalog" translate="label" sortOrder="200"> <label>Catalog</label> </tab> + <tab id="advanced" translate="label" sortOrder="999999"> + <label>Advanced</label> + </tab> <section id="catalog" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1"> <class>separator-top</class> <label>Catalog</label> @@ -193,5 +196,19 @@ </field> </group> </section> + <section id="system" translate="label" type="text" sortOrder="900" showInDefault="1" showInWebsite="1" showInStore="1"> + <class>separator-top</class> + <label>System</label> + <tab>advanced</tab> + <resource>Magento_Config::config_system</resource> + <group id="upload_configuration" translate="label" type="text" sortOrder="1000" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Images Upload Configuration</label> + <field id="jpeg_quality" translate="label comment" type="text" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <label>Quality</label> + <validate>validate-greater-than-zero validate-number required-entry digits-range-1-100</validate> + <comment>Jpeg quality for images 1-100%.</comment> + </field> + </group> + </section> </system> </config> diff --git a/app/code/Magento/Catalog/etc/config.xml b/app/code/Magento/Catalog/etc/config.xml index f52760aa50743..9c9054dd0ce22 100644 --- a/app/code/Magento/Catalog/etc/config.xml +++ b/app/code/Magento/Catalog/etc/config.xml @@ -66,6 +66,9 @@ <product_custom_options_fodler>custom_options</product_custom_options_fodler> </allowed_resources> </media_storage_configuration> + <upload_configuration> + <jpeg_quality>80</jpeg_quality> + </upload_configuration> </system> <design> <watermark> From f67fe209496c7a674444816ca42157cce94ca3f3 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Fri, 5 Oct 2018 12:14:10 +0300 Subject: [PATCH 0154/1158] MAGETWO-95329: Customer can place order with new addresses that was edited during checkout with several conditions --- ...eckoutFillNewBillingAddressActionGroup.xml | 6 +- .../Mftf/Section/CheckoutShippingSection.xml | 3 + ...OrderWithNewAddressesThatWasEditedTest.xml | 93 +++++++++++++++++++ ...omerDashboardAccountInformationSection.xml | 3 + .../StorefrontCustomerOrderViewSection.xml | 2 + 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml index 5a71b82c15cdb..27e5ed7b6e9ab 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml @@ -44,5 +44,9 @@ <selectOption stepKey="selectCounty" selector="{{classPrefix}} {{CheckoutShippingSection.country}}" userInput="{{Address.country_id}}"/> <waitForPageLoad stepKey="waitForFormUpdate2"/> </actionGroup> - + <!--Filling address without second address field and without state field--> + <actionGroup name="LoggedInCheckoutWithOneAddressFieldWithoutStateField" extends="LoggedInCheckoutFillNewBillingAddressActionGroup"> + <remove keyForRemoval="fillStreetAddress2"/> + <remove keyForRemoval="selectState"/> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml index 494a365ffd507..069e2c74430d3 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml @@ -32,5 +32,8 @@ <element name="firstShippingMethod" type="radio" selector="//*[@id='checkout-shipping-method-load']//input[@class='radio']"/> <element name="defaultShipping" type="button" selector=".billing-address-details"/> <element name="stateInput" type="input" selector="input[name=region]"/> + <element name="newAddressModalPopup" type="block" selector=".modal-popup.modal-slide._inner-scroll"/> + <element name="editNewAddress" type="button" selector="//div[@class='shipping-address-item selected-item']//span[text()='Edit']" timeout="30"/> + <element name="closeAddressModalPopup" type="button" selector=".action-hide-popup"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml new file mode 100644 index 0000000000000..c834f8dd9ece9 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest"> + <annotations> + <features value="Checkout"/> + <stories value="Checkout via the Storefront"/> + <title value="Customer Checkout"/> + <description value="Customer can place order with new addresses."/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-67837"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + </before> + <after> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + </after> + <!--Go to Storefront as Customer--> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$createCustomer$$" /> + </actionGroup> + + <!-- Add simple product to cart and go to checkout--> + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart" /> + + <!-- Click "+ New Address" and Fill new address--> + <click selector="{{CheckoutShippingSection.newAddressButton}}" stepKey="addAddress"/> + <actionGroup ref="LoggedInCheckoutWithOneAddressFieldWithoutStateField" stepKey="changeAddress"> + <argument name="Address" value="UK_Not_Default_Address"/> + <argument name="classPrefix" value="._show"/> + </actionGroup> + + <!--Click "Save Addresses" --> + <click selector="{{CheckoutShippingSection.saveAddress}}" stepKey="saveAddress"/> + <waitForPageLoad stepKey="waitForAddressSaved"/> + <dontSeeElement selector="{{CheckoutShippingSection.newAddressModalPopup}}" stepKey="dontSeeModalPopup"/> + + <!--Select Shipping Rate "Flat Rate"--> + <click selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" stepKey="selectFlatShippingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask2"/> + + <!--Click "Edit" for the new address and clear required fields--> + <click selector="{{CheckoutShippingSection.editNewAddress}}" stepKey="editNewAddress"/> + <clearField selector="._show {{CheckoutShippingSection.firstName}}" stepKey="clearFieldFirstName"/> + <clearField selector="._show {{CheckoutShippingSection.lastName}}" stepKey="clearFieldLastName"/> + <clearField selector="._show {{CheckoutShippingSection.street}}" stepKey="clearFieldStreetAddress1"/> + <clearField selector="._show {{CheckoutShippingSection.city}}" stepKey="clearFieldCityName"/> + <clearField selector="._show {{CheckoutShippingSection.postcode}}" stepKey="clearFieldZip"/> + <selectOption selector="._show {{CheckoutShippingSection.country}}" userInput="" stepKey="clearFieldCounty"/> + <clearField selector="._show {{CheckoutShippingSection.telephone}}" stepKey="clearFieldPhoneNumber"/> + + <!--Close Popup and click next--> + <click selector="{{CheckoutShippingSection.closeAddressModalPopup}}" stepKey="closePopup"/> + <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> + + <!--Refresh Page and Place Order--> + <reloadPage stepKey="reloadPage"/> + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <seeElement selector="{{CheckoutSuccessMainSection.success}}" stepKey="orderIsSuccessfullyPlaced"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderLink}}" stepKey="grabOrderNumber"/> + + <!--Verify New addresses in Customer's Address Book--> + <amOnPage url="customer/address/" stepKey="goToCustomerAddressBook"/> + <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" + selector="{{StorefrontCustomerAddressBookSection.addressesList}}" stepKey="checkNewAddresses"/> + <!--Order review page has address that was created during checkout--> + <amOnPage url="sales/order/view/order_id/$grabOrderNumber" stepKey="goToOrderReviewPage"/> + <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" + selector="{{StorefrontCustomerOrderViewSection.shippingAddress}}" stepKey="checkShippingAddress"/> + <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" + selector="{{StorefrontCustomerOrderViewSection.billingAddress}}" stepKey="checkBillingAddress"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml index 70d1bb6675db5..a20193f85ed57 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml @@ -24,4 +24,7 @@ <element name="country" type="select" selector="#country"/> <element name="saveAddress" type="button" selector="[data-action='save-address']" timeout="30"/> </section> + <section name="StorefrontCustomerAddressBookSection"> + <element name="addressesList" type="text" selector="//ol[@class='items addresses']//li[@class='item']" /> + </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrderViewSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrderViewSection.xml index 81612d1c64334..f831aabddd4ee 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrderViewSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrderViewSection.xml @@ -14,5 +14,7 @@ <element name="subtotal" type="text" selector=".subtotal .amount"/> <element name="paymentMethod" type="text" selector=".payment-method dt"/> <element name="printOrderLink" type="text" selector="a.action.print" timeout="30"/> + <element name="shippingAddress" type="text" selector=".box.box-order-shipping-address"/> + <element name="billingAddress" type="text" selector=".box.box-order-billing-address"/> </section> </sections> From c58160625d6bca174b0751f1b671b5ec195b2637 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Fri, 5 Oct 2018 12:27:10 +0300 Subject: [PATCH 0155/1158] MAGETWO-93769: Catalog performance improvements --- app/code/Magento/Catalog/Model/ProductIdLocator.php | 2 +- .../Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductIdLocator.php b/app/code/Magento/Catalog/Model/ProductIdLocator.php index 4c4e6b416527b..8c42821d31697 100644 --- a/app/code/Magento/Catalog/Model/ProductIdLocator.php +++ b/app/code/Magento/Catalog/Model/ProductIdLocator.php @@ -86,7 +86,7 @@ public function retrieveProductIdsBySkus(array $skus) $pages = $collection->getLastPageNumber(); for ($currentPage = 1; $currentPage <= $pages; $currentPage++) { $collection->setCurPage($currentPage); - foreach ($collection->getIterator() as $item) { + foreach ($collection->getItems() as $item) { $sku = strtolower(trim($item->getSku())); $itemIdentifier = $item->getData($linkField); $this->idsBySku[$sku][$itemIdentifier] = $item->getTypeId(); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php index 6455aa58dd234..b9cb82274c808 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php @@ -60,7 +60,7 @@ public function testRetrieveProductIdsBySkus() $collection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class) ->setMethods( [ - 'getIterator', + 'getItems', 'addFieldToFilter', 'setPageSize', 'getLastPageNumber', @@ -78,7 +78,7 @@ public function testRetrieveProductIdsBySkus() $this->collectionFactory->expects($this->once())->method('create')->willReturn($collection); $collection->expects($this->once())->method('addFieldToFilter') ->with(\Magento\Catalog\Api\Data\ProductInterface::SKU, ['in' => $skus])->willReturnSelf(); - $collection->expects($this->atLeastOnce())->method('getIterator')->willReturn(new \ArrayIterator([$product])); + $collection->expects($this->atLeastOnce())->method('getItems')->willReturn([$product]); $collection->expects($this->atLeastOnce())->method('setPageSize')->willReturnSelf(); $collection->expects($this->atLeastOnce())->method('getLastPageNumber')->willReturn(1); $collection->expects($this->atLeastOnce())->method('setCurPage')->with(1)->willReturnSelf(); From 6209f4107673c89b134e2aacd3a23ae708f383ef Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Thu, 4 Oct 2018 13:50:15 +0300 Subject: [PATCH 0156/1158] MAGETWO-91784: On Payment screen up and down arrow key allow to add -ve numbers - Trim the first dash in "Credit Card Number" field --- .../credit-card-validation/credit-card-number-validator.js | 2 +- .../base/web/js/model/credit-card-validation/validator.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js index 8fb12093e36e4..785b636d5832f 100644 --- a/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js +++ b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js @@ -36,7 +36,7 @@ define([ return resultWrapper(null, false, false); } - value = value.replace(/\-|\s/g, ''); + value = value.replace(/|\s/g, ''); if (!/^\d*$/.test(value)) { return resultWrapper(null, false, false); diff --git a/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js index c6f1bad31fc07..f9af514a6d4da 100644 --- a/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js +++ b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js @@ -23,6 +23,12 @@ }(function ($, cvvValidator, creditCardNumberValidator, yearValidator, monthValidator, creditCardData) { 'use strict'; + $('.payment-method-content input[type="number"]').on('keyup', function() { + if ($(this).val() < 0) { + $(this).val($(this).val().replace(/^-/, '')); + } + }); + $.each({ 'validate-card-type': [ function (number, item, allowedTypes) { From a71bea80510b8db011812f7052d5f227ebbf2901 Mon Sep 17 00:00:00 2001 From: vprohorov <prohorov.vital@gmail.com> Date: Mon, 17 Sep 2018 11:47:18 +0300 Subject: [PATCH 0157/1158] MAGETWO-62728: My Wishlist - quantity input box issue - Adding min/max qty checks - Adding js validation --- .../Customer/Wishlist/Item/Column/Cart.php | 26 +++++++++ .../frontend/templates/item/column/cart.phtml | 3 +- .../view/frontend/web/js/add-to-wishlist.js | 56 ++++++++++--------- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/app/code/Magento/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php b/app/code/Magento/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php index b043a8d4b684c..fe0683a52fe97 100644 --- a/app/code/Magento/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php +++ b/app/code/Magento/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php @@ -6,6 +6,8 @@ namespace Magento\Wishlist\Block\Customer\Wishlist\Item\Column; +use Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter; + /** * Wishlist block customer item cart column * @@ -35,4 +37,28 @@ public function getProductItem() { return $this->getItem()->getProduct(); } + + /** + * Get min and max qty for wishlist form. + * + * @return array + */ + public function getMinMaxQty() + { + $stockItem = $this->stockRegistry->getStockItem( + $this->getItem()->getProduct()->getId(), + $this->getItem()->getProduct()->getStore()->getWebsiteId() + ); + + $params = []; + + $params['minAllowed'] = (float)$stockItem->getMinSaleQty(); + if ($stockItem->getMaxSaleQty()) { + $params['maxAllowed'] = (float)$stockItem->getMaxSaleQty(); + } else { + $params['maxAllowed'] = (float)StockDataFilter::MAX_QTY_VALUE; + } + + return $params; + } } diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml index e124edc6a43e1..c1cccae85971c 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml @@ -11,6 +11,7 @@ /** @var \Magento\Wishlist\Model\Item $item */ $item = $block->getItem(); $product = $item->getProduct(); +$allowedQty = $block->getMinMaxQty(); ?> <?php foreach ($block->getChildNames() as $childName): ?> <?= /* @noEscape */ $block->getLayout()->renderElement($childName, false) ?> @@ -21,7 +22,7 @@ $product = $item->getProduct(); <div class="field qty"> <label class="label" for="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]"><span><?= $block->escapeHtml(__('Qty')) ?></span></label> <div class="control"> - <input type="number" data-role="qty" id="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" class="input-text qty" data-validate="{'required-number':true,'validate-greater-than-zero':true,'maxlength':8}" + <input type="number" data-role="qty" id="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" class="input-text qty" data-validate="{'required-number':true,'validate-greater-than-zero':true, 'validate-item-quantity':{'minAllowed':<?= $allowedQty['minAllowed'] ?>,'maxAllowed':<?= $allowedQty['maxAllowed'] ?>}}" name="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" value="<?= /* @noEscape */ (int)($block->getAddToCartQty($item) * 1) ?>"> </div> </div> diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js index 7ce934317263b..db5f77348b2c0 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js @@ -63,12 +63,6 @@ define([ isFileUploaded = false, self = this; - if (event.handleObj.selector == this.options.qtyInfo) { //eslint-disable-line eqeqeq - this._updateAddToWishlistButton({}); - event.stopPropagation(); - - return; - } $(event.handleObj.selector).each(function (index, element) { if ($(element).is('input[type=text]') || $(element).is('input[type=email]') || @@ -89,9 +83,7 @@ define([ } }); - if (isFileUploaded) { - this.bindFormSubmit(); - } + this.bindFormSubmit(isFileUploaded); this._updateAddToWishlistButton(dataToAdd); event.stopPropagation(); }, @@ -195,34 +187,44 @@ define([ /** * Bind form submit. + * + @param {boolean} isFileUploaded */ - bindFormSubmit: function () { + bindFormSubmit: function (isFileUploaded) { var self = this; $('[data-action="add-to-wishlist"]').on('click', function (event) { var element, params, form, action; - event.stopPropagation(); - event.preventDefault(); + if (!$($(self.options.qtyInfo).closest('form')).valid()) { + event.stopPropagation(); + event.preventDefault(); + return; + } - element = $('input[type=file]' + self.options.customOptionsInfo); - params = $(event.currentTarget).data('post'); - form = $(element).closest('form'); - action = params.action; + if (isFileUploaded) { - if (params.data.id) { - $('<input>', { - type: 'hidden', - name: 'id', - value: params.data.id - }).appendTo(form); - } + element = $('input[type=file]' + self.options.customOptionsInfo); + params = $(event.currentTarget).data('post'); + form = $(element).closest('form'); + action = params.action; - if (params.data.uenc) { - action += 'uenc/' + params.data.uenc; - } + if (params.data.id) { + $('<input>', { + type: 'hidden', + name: 'id', + value: params.data.id + }).appendTo(form); + } - $(form).attr('action', action).submit(); + if (params.data.uenc) { + action += 'uenc/' + params.data.uenc; + } + + $(form).attr('action', action).submit(); + event.stopPropagation(); + event.preventDefault(); + } }); } }); From 03e8408b6184d3478251f30cc69956a06752503f Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Fri, 5 Oct 2018 13:51:24 +0300 Subject: [PATCH 0158/1158] MAGETWO-91636: Tooltip Position on Mobile out of view range - Fix css styles for 768px --- .../web/css/source/module/checkout/_tooltip.less | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less index 273f626ec03d6..bf264a98f33b8 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less @@ -137,9 +137,12 @@ } } -.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { +.media-width(@extremum, @break) when (@extremum = 'max') and (@break >= @screen__m) { .field-tooltip { .field-tooltip-content { + .lib-css(right, @checkout-tooltip-content-mobile__right); + .lib-css(top, @checkout-tooltip-content-mobile__top); + left: auto; &:extend(.abs-checkout-tooltip-content-position-top-mobile all); } } From e194b139c8889587a90aca5cee470e0a40f26422 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Fri, 5 Oct 2018 14:04:50 +0300 Subject: [PATCH 0159/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- app/code/Magento/Catalog/Helper/Image.php | 1 + .../Magento/Catalog/Model/Product/Image.php | 17 +++++++++++++---- .../Model/Product/Image/ParamsBuilder.php | 9 +++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Catalog/Helper/Image.php b/app/code/Magento/Catalog/Helper/Image.php index 758e59790d241..74153267f41d6 100644 --- a/app/code/Magento/Catalog/Helper/Image.php +++ b/app/code/Magento/Catalog/Helper/Image.php @@ -298,6 +298,7 @@ public function resize($width, $height = null) * * @param int $quality * @return $this + * @deprecated */ public function setQuality($quality) { diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php index f1ae9ac62dc9b..564b817fc167e 100644 --- a/app/code/Magento/Catalog/Model/Product/Image.php +++ b/app/code/Magento/Catalog/Model/Product/Image.php @@ -24,6 +24,11 @@ */ class Image extends \Magento\Framework\Model\AbstractModel { + /** + * Config path for the jpeg image quality value + */ + const XML_PATH_JPEG_QUALITY = 'system/upload_configuration/jpeg_quality'; + /** * @var int */ @@ -38,8 +43,9 @@ class Image extends \Magento\Framework\Model\AbstractModel * Default quality value (for JPEG images only). * * @var int + * @deprecated */ - protected $_quality = 80; + protected $_quality = null; /** * @var bool @@ -289,6 +295,7 @@ public function getHeight() * * @param int $quality * @return $this + * @deprecated */ public function setQuality($quality) { @@ -303,7 +310,9 @@ public function setQuality($quality) */ public function getQuality() { - return $this->_quality; + return $this->_quality === null + ? $this->_scopeConfig->getValue(self::XML_PATH_JPEG_QUALITY) + : $this->_quality; } /** @@ -461,7 +470,7 @@ public function getImageProcessor() $this->_processor->keepTransparency($this->_keepTransparency); $this->_processor->constrainOnly($this->_constrainOnly); $this->_processor->backgroundColor($this->_backgroundColor); - $this->_processor->quality($this->_quality); + $this->_processor->quality($this->getQuality()); return $this->_processor; } @@ -843,7 +852,7 @@ private function getMiscParams() 'transparency' => $this->_keepTransparency, 'background' => $this->_backgroundColor, 'angle' => $this->_angle, - 'quality' => $this->_quality + 'quality' => $this->getQuality() ] ); } diff --git a/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php b/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php index dd8d352fecebc..21fde84931fa6 100644 --- a/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php +++ b/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php @@ -10,17 +10,13 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\View\ConfigInterface; use Magento\Store\Model\ScopeInterface; +use Magento\Catalog\Model\Product\Image; /** * Builds parameters array used to build Image Asset */ class ParamsBuilder { - /** - * @var int - */ - private $defaultQuality = 80; - /** * @var array */ @@ -100,11 +96,12 @@ private function overwriteDefaultValues(array $imageArguments): array $transparency = $imageArguments['transparency'] ?? $this->defaultKeepTransparency; $background = $imageArguments['background'] ?? $this->defaultBackground; $angle = $imageArguments['angle'] ?? $this->defaultAngle; + $quality = (int) $this->scopeConfig->getValue(Image::XML_PATH_JPEG_QUALITY); return [ 'background' => (array) $background, 'angle' => $angle, - 'quality' => $this->defaultQuality, + 'quality' => $quality, 'keep_aspect_ratio' => (bool) $aspectRatio, 'keep_frame' => (bool) $frame, 'keep_transparency' => (bool) $transparency, From 5fb7cf4c4f97255622f413a4a33667ae093e032d Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Fri, 5 Oct 2018 15:24:45 +0300 Subject: [PATCH 0160/1158] MAGETWO-93769: Catalog performance improvements --- .../Catalog/Model/Product/Price/TierPriceStorage.php | 8 ++++---- app/code/Magento/Catalog/Model/ProductIdLocator.php | 12 +++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php b/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php index 7298e650bd448..3ee064670a460 100644 --- a/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php +++ b/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php @@ -97,7 +97,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function get(array $skus) { @@ -107,7 +107,7 @@ public function get(array $skus) } /** - * {@inheritdoc} + * @inheritdoc */ public function update(array $prices) { @@ -128,7 +128,7 @@ public function update(array $prices) } /** - * {@inheritdoc} + * @inheritdoc */ public function replace(array $prices) { @@ -144,7 +144,7 @@ public function replace(array $prices) } /** - * {@inheritdoc} + * @inheritdoc */ public function delete(array $prices) { diff --git a/app/code/Magento/Catalog/Model/ProductIdLocator.php b/app/code/Magento/Catalog/Model/ProductIdLocator.php index 8c42821d31697..2d382164f2649 100644 --- a/app/code/Magento/Catalog/Model/ProductIdLocator.php +++ b/app/code/Magento/Catalog/Model/ProductIdLocator.php @@ -63,7 +63,17 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc + * + * Load product items by provided products SKUs. + * Products collection will be iterated by pages with the $this->batchSize as a page size (for a cases when to many + * products SKUs were provided in parameters. + * Loaded products will be chached in the $this->idsBySku variable, but in the end of the method these storage will + * be truncated to $idsLimit quantity. + * As a result array with the products data will be returned with the following scheme: + * $data['product_sku']['link_field_value' => 'product_type'] + * + * @throws \Exception */ public function retrieveProductIdsBySkus(array $skus) { From 8cf76a56cb7d4eb43489e223240f17868a2b8ca4 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Fri, 5 Oct 2018 16:30:57 +0300 Subject: [PATCH 0161/1158] MAGETWO-91517: Cancel and Return link removes billing and shipping address - Fix statics. --- .../frontend/web/js/model/checkout-data-resolver.js | 13 ++++++++----- .../view/frontend/web/js/view/form/element/email.js | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js index 25abe3c4ed3a0..4abb4c4d61700 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js @@ -66,14 +66,15 @@ define([ * Resolve shipping address. Used local storage */ resolveShippingAddress: function () { + var newCustomerShippingAddress; + if (!checkoutData.getShippingAddressFromData() && window.checkoutConfig.shippingAddressFromData ) { checkoutData.setShippingAddressFromData(window.checkoutConfig.shippingAddressFromData); } - var newCustomerShippingAddress = checkoutData.getNewCustomerShippingAddress(); - + newCustomerShippingAddress = checkoutData.getNewCustomerShippingAddress(); if (newCustomerShippingAddress) { createShippingAddress(newCustomerShippingAddress); } @@ -201,15 +202,17 @@ define([ * Resolve billing address. Used local storage */ resolveBillingAddress: function () { + var selectedBillingAddress, + newCustomerBillingAddressData; + if (!checkoutData.getBillingAddressFromData() && window.checkoutConfig.billingAddressFromData ) { checkoutData.setBillingAddressFromData(window.checkoutConfig.billingAddressFromData); } - var selectedBillingAddress = checkoutData.getSelectedBillingAddress(), - newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress(); - + selectedBillingAddress = checkoutData.getSelectedBillingAddress(); + newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress(); if (selectedBillingAddress) { if (selectedBillingAddress == 'new-customer-address' && newCustomerBillingAddressData) { //eslint-disable-line selectBillingAddress(createBillingAddress(newCustomerBillingAddressData)); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js index 6c0075fca6d51..37a785e292365 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js @@ -17,6 +17,8 @@ define([ ], function ($, Component, ko, customer, checkEmailAvailability, loginAction, quote, checkoutData, fullScreenLoader) { 'use strict'; + var validatedEmail; + if (!checkoutData.getValidatedEmailValue() && window.checkoutConfig.validatedEmailValue ) { @@ -24,8 +26,7 @@ define([ checkoutData.setValidatedEmailValue(window.checkoutConfig.validatedEmailValue); } - var validatedEmail = checkoutData.getValidatedEmailValue(); - + validatedEmail = checkoutData.getValidatedEmailValue(); if (validatedEmail && !customer.isLoggedIn()) { quote.guestEmail = validatedEmail; } From c8a059dc87f1ce4c478d052ba1795e6d92f2cceb Mon Sep 17 00:00:00 2001 From: Stsiapan Korf <Stsiapan_Korf@epam.com> Date: Fri, 5 Oct 2018 16:23:53 +0300 Subject: [PATCH 0162/1158] MAGETWO-91496: Instantiating WYSIWYG in DynamicRows - Add wysiwyg suffix to html and js --- .../view/base/web/js/form/element/wysiwyg.js | 20 +++++++++++++++---- .../Framework/Data/Form/Element/Editor.php | 8 ++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js index 6507da5e1a933..0c11ceeb03dae 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js @@ -20,6 +20,7 @@ define([ return Abstract.extend({ defaults: { elementSelector: 'textarea', + suffixRegExpPattern: '\\${ \\$.wysiwygUniqueSuffix }', value: '', $wysiwygEditorButton: '', links: { @@ -61,12 +62,23 @@ define([ return this; }, + /** @inheritdoc */ + initConfig: function (config) { + var pattern = config.suffixRegExpPattern || this.constructor.defaults.suffixRegExpPattern; + + config.content = config.content.replace(new RegExp(pattern, 'g'), this.getUniqueSuffix(config)); + this._super(); + + return this; + }, + /** - * @inheritdoc + * Build unique id based on name, underscore separated. + * + * @param {Object} config */ - destroy: function () { - this._super(); - wysiwyg.removeEvents(this.wysiwygId); + getUniqueSuffix: function (config) { + return config.name.replace(/(\.|-)/g, '_'); }, /** diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php index c438edf3aa9ac..dee0b6c842f5f 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php @@ -542,4 +542,12 @@ protected function getInlineJs($jsSetupObject, $forceLoad) </script>'; return $jsString; } + + /** + * @inheritdoc + */ + public function getHtmlId() + { + return parent::getHtmlId() . '${ $.wysiwygUniqueSuffix }'; + } } From fa250373443e0a10e9f9472cff69d33754740382 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Fri, 5 Oct 2018 17:11:59 +0300 Subject: [PATCH 0163/1158] MAGETWO-95329: Customer can place order with new addresses that was edited during checkout with several conditions --- ...eckoutFillNewBillingAddressActionGroup.xml | 16 +++++++++++ .../Test/Mftf/Page/CheckoutShippingPage.xml | 1 + .../CheckoutNewAddressModalPopupSection.xml | 15 ++++++++++ .../Mftf/Section/CheckoutShippingSection.xml | 4 +-- ...OrderWithNewAddressesThatWasEditedTest.xml | 28 +++++++++---------- .../Page/StorefrontCustomerAddressesPage.xml | 14 ++++++++++ .../StorefrontCustomerAddressesSection.xml | 14 ++++++++++ ...omerDashboardAccountInformationSection.xml | 3 -- 8 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerAddressesPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml index 27e5ed7b6e9ab..62dd6b67b78a6 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillNewBillingAddressActionGroup.xml @@ -49,4 +49,20 @@ <remove keyForRemoval="fillStreetAddress2"/> <remove keyForRemoval="selectState"/> </actionGroup> + + <actionGroup name="clearCheckoutAddressPopupFieldsActionGroup"> + <arguments> + <argument name="classPrefix" type="string" defaultValue=""/> + </arguments> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.firstName}}" stepKey="clearFieldFirstName"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.lastName}}" stepKey="clearFieldLastName"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.company}}" stepKey="clearFieldCompany"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.street}}" stepKey="clearFieldStreetAddress1"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.street2}}" stepKey="clearFieldStreetAddress2"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.city}}" stepKey="clearFieldCityName"/> + <selectOption selector="{{classPrefix}} {{CheckoutShippingSection.region}}" userInput="" stepKey="clearFieldRegion"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.postcode}}" stepKey="clearFieldZip"/> + <selectOption selector="{{classPrefix}} {{CheckoutShippingSection.country}}" userInput="" stepKey="clearFieldCounty"/> + <clearField selector="{{classPrefix}} {{CheckoutShippingSection.telephone}}" stepKey="clearFieldPhoneNumber"/> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml index 07f9e9e6481f7..d13c2d265462b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml @@ -11,5 +11,6 @@ <page name="CheckoutShippingPage" url="/checkout/#shipping" module="Checkout" area="storefront"> <section name="CheckoutShippingGuestInfoSection"/> <section name="CheckoutShippingSection"/> + <section name="CheckoutNewAddressModalPopupSection"/> </page> </pages> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml new file mode 100644 index 0000000000000..1c523670f7dbb --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="CheckoutNewAddressModalPopupSection"> + <element name="newAddressModalPopup" type="block" selector=".modal-popup.modal-slide._inner-scroll"/> + <element name="closeAddressModalPopup" type="button" selector=".action-hide-popup"/> + </section> +</sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml index 069e2c74430d3..cff960946565d 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml @@ -32,8 +32,6 @@ <element name="firstShippingMethod" type="radio" selector="//*[@id='checkout-shipping-method-load']//input[@class='radio']"/> <element name="defaultShipping" type="button" selector=".billing-address-details"/> <element name="stateInput" type="input" selector="input[name=region]"/> - <element name="newAddressModalPopup" type="block" selector=".modal-popup.modal-slide._inner-scroll"/> - <element name="editNewAddress" type="button" selector="//div[@class='shipping-address-item selected-item']//span[text()='Edit']" timeout="30"/> - <element name="closeAddressModalPopup" type="button" selector=".action-hide-popup"/> + <element name="editActiveAddress" type="button" selector="//div[@class='shipping-address-item selected-item']//span[text()='Edit']" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml index c834f8dd9ece9..0283f6bd108ec 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml @@ -12,7 +12,7 @@ <annotations> <features value="Checkout"/> <stories value="Checkout via the Storefront"/> - <title value="Customer Checkout"/> + <title value="Customer can place order with new addresses that was edited during checkout with several conditions"/> <description value="Customer can place order with new addresses."/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-67837"/> @@ -51,24 +51,19 @@ <!--Click "Save Addresses" --> <click selector="{{CheckoutShippingSection.saveAddress}}" stepKey="saveAddress"/> <waitForPageLoad stepKey="waitForAddressSaved"/> - <dontSeeElement selector="{{CheckoutShippingSection.newAddressModalPopup}}" stepKey="dontSeeModalPopup"/> + <dontSeeElement selector="{{CheckoutNewAddressModalPopupSection.newAddressModalPopup}}" stepKey="dontSeeModalPopup"/> <!--Select Shipping Rate "Flat Rate"--> <click selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" stepKey="selectFlatShippingMethod"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask2"/> - <!--Click "Edit" for the new address and clear required fields--> - <click selector="{{CheckoutShippingSection.editNewAddress}}" stepKey="editNewAddress"/> - <clearField selector="._show {{CheckoutShippingSection.firstName}}" stepKey="clearFieldFirstName"/> - <clearField selector="._show {{CheckoutShippingSection.lastName}}" stepKey="clearFieldLastName"/> - <clearField selector="._show {{CheckoutShippingSection.street}}" stepKey="clearFieldStreetAddress1"/> - <clearField selector="._show {{CheckoutShippingSection.city}}" stepKey="clearFieldCityName"/> - <clearField selector="._show {{CheckoutShippingSection.postcode}}" stepKey="clearFieldZip"/> - <selectOption selector="._show {{CheckoutShippingSection.country}}" userInput="" stepKey="clearFieldCounty"/> - <clearField selector="._show {{CheckoutShippingSection.telephone}}" stepKey="clearFieldPhoneNumber"/> + <click selector="{{CheckoutShippingSection.editActiveAddress}}" stepKey="editNewAddress"/> + <actionGroup ref="clearCheckoutAddressPopupFieldsActionGroup" stepKey="clearRequiredFields"> + <argument name="classPrefix" value="._show"/> + </actionGroup> <!--Close Popup and click next--> - <click selector="{{CheckoutShippingSection.closeAddressModalPopup}}" stepKey="closePopup"/> + <click selector="{{CheckoutNewAddressModalPopupSection.closeAddressModalPopup}}" stepKey="closePopup"/> <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" stepKey="waitForNextButton"/> <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> @@ -80,14 +75,17 @@ <grabTextFrom selector="{{CheckoutSuccessMainSection.orderLink}}" stepKey="grabOrderNumber"/> <!--Verify New addresses in Customer's Address Book--> - <amOnPage url="customer/address/" stepKey="goToCustomerAddressBook"/> + <amOnPage url="{{StorefrontCustomerAddressesPage.url}}" stepKey="goToCustomerAddressBook"/> <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" - selector="{{StorefrontCustomerAddressBookSection.addressesList}}" stepKey="checkNewAddresses"/> + selector="{{StorefrontCustomerAddressesSection.addressesList}}" stepKey="checkNewAddresses"/> <!--Order review page has address that was created during checkout--> - <amOnPage url="sales/order/view/order_id/$grabOrderNumber" stepKey="goToOrderReviewPage"/> + <amOnPage url="{{StorefrontCustomerOrderViewPage.url({$grabOrderNumber})}}" stepKey="goToOrderReviewPage"/> <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" selector="{{StorefrontCustomerOrderViewSection.shippingAddress}}" stepKey="checkShippingAddress"/> <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" selector="{{StorefrontCustomerOrderViewSection.billingAddress}}" stepKey="checkBillingAddress"/> + + <!--Logout from customer account--> + <amOnPage url="customer/account/logout/" stepKey="logoutCustomer"/> </test> </tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerAddressesPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerAddressesPage.xml new file mode 100644 index 0000000000000..b9bede5133060 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerAddressesPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="StorefrontCustomerAddressesPage" url="/customer/address/" area="storefront" module="Magento_Customer"> + <section name="StorefrontCustomerAddressesSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml new file mode 100644 index 0000000000000..8a6a98ff45a6a --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontCustomerAddressesSection"> + <element name="addressesList" type="text" selector=".block-addresses-list" /> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml index a20193f85ed57..70d1bb6675db5 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerDashboardAccountInformationSection.xml @@ -24,7 +24,4 @@ <element name="country" type="select" selector="#country"/> <element name="saveAddress" type="button" selector="[data-action='save-address']" timeout="30"/> </section> - <section name="StorefrontCustomerAddressBookSection"> - <element name="addressesList" type="text" selector="//ol[@class='items addresses']//li[@class='item']" /> - </section> </sections> From 77af6f7d21949eaac1866dfbbbfb4ec1b424a407 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Fri, 5 Oct 2018 17:14:37 +0300 Subject: [PATCH 0164/1158] MAGETWO-95329: Customer can place order with new addresses that was edited during checkout with several conditions --- .../Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml | 2 +- ...pupSection.xml => StorefrontCheckoutAddressPopupSection.xml} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/code/Magento/Checkout/Test/Mftf/Section/{CheckoutNewAddressModalPopupSection.xml => StorefrontCheckoutAddressPopupSection.xml} (90%) diff --git a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml index d13c2d265462b..c8641f7d8fbf3 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml @@ -11,6 +11,6 @@ <page name="CheckoutShippingPage" url="/checkout/#shipping" module="Checkout" area="storefront"> <section name="CheckoutShippingGuestInfoSection"/> <section name="CheckoutShippingSection"/> - <section name="CheckoutNewAddressModalPopupSection"/> + <section name="StorefrontCheckoutAddressPopupSection"/> </page> </pages> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutAddressPopupSection.xml similarity index 90% rename from app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml rename to app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutAddressPopupSection.xml index 1c523670f7dbb..6a27915768dd7 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutNewAddressModalPopupSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutAddressPopupSection.xml @@ -8,7 +8,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="CheckoutNewAddressModalPopupSection"> + <section name="StorefrontCheckoutAddressPopupSection"> <element name="newAddressModalPopup" type="block" selector=".modal-popup.modal-slide._inner-scroll"/> <element name="closeAddressModalPopup" type="button" selector=".action-hide-popup"/> </section> From d2c2c0067d19b1624e757776695ad19be4c49f52 Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Sat, 6 Oct 2018 12:59:45 +0300 Subject: [PATCH 0165/1158] Fix no results handle layout update --- .../Controller/Advanced/Result.php | 4 +++- .../CatalogSearch/Controller/Result/Index.php | 4 +++- .../Unit/Controller/Advanced/ResultTest.php | 24 +++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php index dfbd46aa6a1cf..6cefacaf785e9 100644 --- a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php +++ b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php @@ -64,7 +64,9 @@ public function execute() $handles = null; if ($size == 0) { - $handles = [static::DEFAULT_NO_RESULT_HANDLE]; + $this->_view->getPage()->initLayout(); + $handles = $this->_view->getLayout()->getUpdate()->getHandles(); + $handles[] = static::DEFAULT_NO_RESULT_HANDLE; } $this->_view->loadLayout($handles); diff --git a/app/code/Magento/CatalogSearch/Controller/Result/Index.php b/app/code/Magento/CatalogSearch/Controller/Result/Index.php index 3e0569ef7bfe8..a016beb0215b4 100644 --- a/app/code/Magento/CatalogSearch/Controller/Result/Index.php +++ b/app/code/Magento/CatalogSearch/Controller/Result/Index.php @@ -95,7 +95,9 @@ public function execute() $handles = null; if ($query->getNumResults() == 0) { - $handles = [static::DEFAULT_NO_RESULT_HANDLE]; + $this->_view->getPage()->initLayout(); + $handles = $this->_view->getLayout()->getUpdate()->getHandles(); + $handles[] = static::DEFAULT_NO_RESULT_HANDLE; } if (empty($getAdditionalRequestParameters) && diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php index d4229ff934e9b..71ba6589eee09 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php @@ -139,9 +139,10 @@ public function testUrlSetOnException() /** @var \Magento\CatalogSearch\Controller\Advanced\Result $instance */ $instance = $objectManager->getObject( \Magento\CatalogSearch\Controller\Advanced\Result::class, - ['context' => $contextMock, - 'catalogSearchAdvanced' => $catalogSearchAdvanced, - 'urlFactory' => $urlFactoryMock + [ + 'context' => $contextMock, + 'catalogSearchAdvanced' => $catalogSearchAdvanced, + 'urlFactory' => $urlFactoryMock ] ); $this->assertEquals($redirectResultMock, $instance->execute()); @@ -151,10 +152,25 @@ public function testNoResultsHandle() { $expectedQuery = 'notExistTerm'; - $view = $this->createPartialMock(\Magento\Framework\App\View::class, ['loadLayout', 'renderLayout']); + $update = $this->createPartialMock(\Magento\Framework\View\Model\Layout\Merge::class, ['getHandles']); + $update->expects($this->once())->method('getHandles')->will($this->returnValue([])); + + $layout = $this->createPartialMock(\Magento\Framework\View\Result\Layout::class, ['getUpdate']); + $layout->expects($this->once())->method('getUpdate')->will($this->returnValue($update)); + + $page = $this->createPartialMock(\Magento\Framework\View\Result\Page::class, ['initLayout']); + + $view = $this->createPartialMock( + \Magento\Framework\App\View::class, + ['loadLayout', 'renderLayout', 'getPage', 'getLayout'] + ); + $view->expects($this->once())->method('loadLayout') ->with([\Magento\CatalogSearch\Controller\Advanced\Result::DEFAULT_NO_RESULT_HANDLE]); + $view->expects($this->once())->method('getPage')->will($this->returnValue($page)); + $view->expects($this->once())->method('getLayout')->will($this->returnValue($layout)); + $request = $this->createPartialMock(\Magento\Framework\App\Console\Request::class, ['getQueryValue']); $request->expects($this->once())->method('getQueryValue')->will($this->returnValue($expectedQuery)); From 87cfb718edcde6b21375e398dbc8fd35cb84dcbe Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Sat, 6 Oct 2018 12:40:15 +0200 Subject: [PATCH 0166/1158] Working concept for setting shipping address for a shopping cart --- .../SetShippingMethodsOnCart.php | 81 +++++++++++++------ .../Magento/QuoteGraphQl/etc/schema.graphqls | 8 +- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php index f2e1be3bb0508..c2d14668a2e70 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php @@ -7,7 +7,8 @@ namespace Magento\QuoteGraphQl\Model\Resolver\ShippingMethod; -use Magento\Framework\Exception\CouldNotSaveException; +use Magento\Checkout\Api\ShippingInformationManagementInterface; +use Magento\Checkout\Model\ShippingInformation; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; @@ -19,8 +20,10 @@ use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\Stdlib\ArrayManager; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; -use Magento\Quote\Model\ShippingMethodManagementInterface; use Magento\QuoteGraphQl\Model\Authorization\IsCartMutationAllowedForCurrentUser; +use Magento\Quote\Model\Quote\AddressFactory as QuoteAddressFactory; +use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; +use Magento\Checkout\Model\ShippingInformationFactory; /** * Class SetShippingMethodsOnCart @@ -29,41 +32,64 @@ */ class SetShippingMethodsOnCart implements ResolverInterface { + /** + * @var ShippingInformationFactory + */ + private $shippingInformationFactory; + + /** + * @var QuoteAddressFactory + */ + private $quoteAddressFactory; + + /** + * @var QuoteAddressResource + */ + private $quoteAddressResource; + /** * @var MaskedQuoteIdToQuoteIdInterface */ private $maskedQuoteIdToQuoteId; + /** * @var ArrayManager */ private $arrayManager; /** - * @var ShippingMethodManagementInterface + * @var IsCartMutationAllowedForCurrentUser */ - private $shippingMethodManagement; + private $isCartMutationAllowedForCurrentUser; /** - * @var IsCartMutationAllowedForCurrentUser + * @var ShippingInformationManagementInterface */ - private $isCartMutationAllowedForCurrentUser; + private $shippingInformationManagement; /** * SetShippingMethodsOnCart constructor. * @param ArrayManager $arrayManager * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId - * @param ShippingMethodManagementInterface $shippingMethodManagement + * @param IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser */ public function __construct( ArrayManager $arrayManager, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - ShippingMethodManagementInterface $shippingMethodManagement, - IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser + IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser, + ShippingInformationManagementInterface $shippingInformationManagement, + QuoteAddressFactory $quoteAddressFacrory, + QuoteAddressResource $quoteAddressResource, + ShippingInformationFactory $shippingInformationFactory ) { $this->arrayManager = $arrayManager; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->shippingMethodManagement = $shippingMethodManagement; $this->isCartMutationAllowedForCurrentUser = $isCartMutationAllowedForCurrentUser; + $this->shippingInformationManagement = $shippingInformationManagement; + + $this->quoteAddressResource = $quoteAddressResource; + $this->quoteAddressFactory = $quoteAddressFacrory; + $this->shippingInformationFactory = $shippingInformationFactory; } /** @@ -77,17 +103,18 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value if (!$maskedCartId) { throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); } - if (!$shippingMethods) { throw new GraphQlInputException(__('Required parameter "shipping_methods" is missing')); } $shippingMethod = reset($shippingMethods); // TODO: provide implementation for multishipping + if (!$shippingMethod['cart_address_id']) { + throw new GraphQlInputException(__('Required parameter "cart_address_id" is missing')); + } if (!$shippingMethod['shipping_carrier_code']) { // FIXME: check the E_WARNING here throw new GraphQlInputException(__('Required parameter "shipping_carrier_code" is missing')); } - if (!$shippingMethod['shipping_method_code']) { // FIXME: check the E_WARNING here throw new GraphQlInputException(__('Required parameter "shipping_method_code" is missing')); } @@ -109,22 +136,28 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value ); } + $quoteAddress = $this->quoteAddressFactory->create(); + $this->quoteAddressResource->load($quoteAddress, $shippingMethod['cart_address_id']); + + /** @var ShippingInformation $shippingInformation */ + $shippingInformation = $this->shippingInformationFactory->create(); + + /* If the address is not a shipping address (but billing) the system will find the proper shipping address for + the selected cart and set the information there (actual for single shipping address) */ + $shippingInformation->setShippingAddress($quoteAddress); + $shippingInformation->setShippingCarrierCode($shippingMethod['shipping_carrier_code']); + $shippingInformation->setShippingMethodCode($shippingMethod['shipping_method_code']); + try { - $this->shippingMethodManagement->set( - $cartId, - $shippingMethods['shipping_carrier_code'], - $shippingMethods['shipping_method_code'] - ); - } catch (InputException $exception) { - throw new GraphQlInputException(__($exception->getMessage())); - } catch (CouldNotSaveException $exception) { - throw new GraphQlInputException(__($exception->getMessage())); - } catch (StateException $exception) { - throw new GraphQlInputException(__($exception->getMessage())); + $this->shippingInformationManagement->saveAddressInformation($cartId, $shippingInformation); } catch (NoSuchEntityException $exception) { throw new GraphQlNoSuchEntityException(__($exception->getMessage())); + } catch (StateException $exception) { + throw new GraphQlInputException(__($exception->getMessage())); + } catch (InputException $exception) { + throw new GraphQlInputException(__($exception->getMessage())); } return 'Success!'; // TODO we should return cart here } -} \ No newline at end of file +} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 45f98daeaed06..730a54377b370 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -6,9 +6,9 @@ type Query { } type Mutation { - createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") - applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") - removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") + createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") + applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") + removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveCouponFromCart") setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ShippingMethod\\SetShippingMethodsOnCart") @@ -53,7 +53,7 @@ input SetShippingMethodsOnCartInput { } input ShippingMethodForAddressInput { - cart_address_id: int + cart_address_id: Int! shipping_carrier_code: String! shipping_method_code: String! } From d4735edfa9ba6fb98007c9073339025571297d22 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Sun, 7 Oct 2018 14:19:30 +0300 Subject: [PATCH 0167/1158] MAGETWO-95329: Customer can place order with new addresses that was edited during checkout with several conditions --- ...ontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml index 0283f6bd108ec..9d805589eb831 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml @@ -51,7 +51,7 @@ <!--Click "Save Addresses" --> <click selector="{{CheckoutShippingSection.saveAddress}}" stepKey="saveAddress"/> <waitForPageLoad stepKey="waitForAddressSaved"/> - <dontSeeElement selector="{{CheckoutNewAddressModalPopupSection.newAddressModalPopup}}" stepKey="dontSeeModalPopup"/> + <dontSeeElement selector="{{StorefrontCheckoutAddressPopupSection.newAddressModalPopup}}" stepKey="dontSeeModalPopup"/> <!--Select Shipping Rate "Flat Rate"--> <click selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" stepKey="selectFlatShippingMethod"/> @@ -63,7 +63,7 @@ </actionGroup> <!--Close Popup and click next--> - <click selector="{{CheckoutNewAddressModalPopupSection.closeAddressModalPopup}}" stepKey="closePopup"/> + <click selector="{{StorefrontCheckoutAddressPopupSection.closeAddressModalPopup}}" stepKey="closePopup"/> <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" stepKey="waitForNextButton"/> <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> From 34e8f843b314da86a4294522e74142b82b89be05 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 8 Oct 2018 10:24:06 +0300 Subject: [PATCH 0168/1158] MAGETWO-95450: Unskip MFTF tests StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest --- ...ntTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml index 9bc44dec0b5b8..9ea4793242fe8 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml @@ -18,9 +18,6 @@ <testCaseId value="MAGETWO-41930"/> <group value="checkout"/> <group value="tax"/> - <skip> - <issueId value="MAGETWO-90966"/> - </skip> </annotations> <before> <!-- Preconditions --> From 18af30faafb267783d004617e75f998c97e3d84f Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Mon, 8 Oct 2018 10:55:38 +0300 Subject: [PATCH 0169/1158] MAGETWO-95329: Customer can place order with new addresses that was edited during checkout with several conditions --- ...PlaceOrderWithNewAddressesThatWasEditedTest.xml | 2 +- .../StorefrontCustomerLogoutActionGroup.xml | 14 ++++++++++++++ .../Mftf/Page/StorefrontCustomerLogoutPage.xml | 11 +++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerLogoutActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerLogoutPage.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml index 9d805589eb831..274e32653d8e6 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml @@ -86,6 +86,6 @@ selector="{{StorefrontCustomerOrderViewSection.billingAddress}}" stepKey="checkBillingAddress"/> <!--Logout from customer account--> - <amOnPage url="customer/account/logout/" stepKey="logoutCustomer"/> + <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="logoutCustomer"/> </test> </tests> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerLogoutActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerLogoutActionGroup.xml new file mode 100644 index 0000000000000..5497b083ab5ad --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerLogoutActionGroup.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontCustomerLogoutActionGroup"> + <amOnPage url="{{StorefrontCustomerLogoutPage.url}}" stepKey="storefrontSignOut"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerLogoutPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerLogoutPage.xml new file mode 100644 index 0000000000000..b3cea8f2c2939 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerLogoutPage.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="StorefrontCustomerLogoutPage" url="customer/account/logout/" area="storefront" module="Magento_Customer"/> +</pages> From 4da3b5410e7525a4ea00b4df7c1c6f5a3f2ae5b4 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Mon, 8 Oct 2018 11:56:39 +0300 Subject: [PATCH 0170/1158] MAGETWO-95329: Customer can place order with new addresses that was edited during checkout with several conditions --- ...tCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml index 274e32653d8e6..cc5e723c72ea0 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml @@ -26,6 +26,9 @@ <createData entity="Simple_US_Customer" stepKey="createCustomer"/> </before> <after> + <!--Logout from customer account--> + <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="logoutCustomer"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> @@ -84,8 +87,5 @@ selector="{{StorefrontCustomerOrderViewSection.shippingAddress}}" stepKey="checkShippingAddress"/> <see userInput="{{UK_Not_Default_Address.street[0]}} {{UK_Not_Default_Address.city}}, {{UK_Not_Default_Address.postcode}}" selector="{{StorefrontCustomerOrderViewSection.billingAddress}}" stepKey="checkBillingAddress"/> - - <!--Logout from customer account--> - <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="logoutCustomer"/> </test> </tests> From 96f608cca3e89f21bfc4a15e84c18220e5b99dca Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun <ogorkun@magento.com> Date: Mon, 8 Oct 2018 13:17:58 +0300 Subject: [PATCH 0171/1158] MAGETWO-94173: Disable backups by default --- .../Block/System/Store/Delete/Form.php | 34 ++- .../Controller/Adminhtml/System/Store.php | 3 + .../Backup/Controller/Adminhtml/Index.php | 26 +- .../Controller/Adminhtml/Index/Disabled.php | 48 ++++ app/code/Magento/Backup/Cron/SystemBackup.php | 7 + app/code/Magento/Backup/Helper/Data.php | 13 + app/code/Magento/Backup/Model/Db.php | 38 ++- .../Test/Unit/Cron/SystemBackupTest.php | 128 ++------- .../Magento/Backup/Test/Unit/Model/DbTest.php | 243 ------------------ .../Magento/Backup/etc/adminhtml/system.xml | 12 +- app/code/Magento/Backup/etc/config.xml | 16 ++ .../layout/backup_index_disabled.xml | 17 ++ .../adminhtml/templates/backup/disabled.phtml | 7 + .../Backup/Test/Repository/ConfigData.xml | 24 ++ .../Backup/Test/TestCase/NavigateMenuTest.xml | 16 -- .../Test/TestCase/DeleteStoreEntityTest.php | 11 +- .../TestCase/DeleteStoreGroupEntityTest.php | 11 +- .../Test/TestCase/DeleteWebsiteEntityTest.php | 11 +- .../TestStep/DeleteWebsitesEntityStep.php | 16 ++ .../Magento/Framework/Backup/DbTest.php | 1 + .../Framework/Backup/BackupInterface.php | 2 + .../Framework/Backup/Db/BackupDbInterface.php | 2 + .../Framework/Backup/Db/BackupInterface.php | 2 + 23 files changed, 304 insertions(+), 384 deletions(-) create mode 100644 app/code/Magento/Backup/Controller/Adminhtml/Index/Disabled.php delete mode 100644 app/code/Magento/Backup/Test/Unit/Model/DbTest.php create mode 100644 app/code/Magento/Backup/etc/config.xml create mode 100644 app/code/Magento/Backup/view/adminhtml/layout/backup_index_disabled.xml create mode 100644 app/code/Magento/Backup/view/adminhtml/templates/backup/disabled.phtml create mode 100644 dev/tests/functional/tests/app/Magento/Backup/Test/Repository/ConfigData.xml delete mode 100644 dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml diff --git a/app/code/Magento/Backend/Block/System/Store/Delete/Form.php b/app/code/Magento/Backend/Block/System/Store/Delete/Form.php index e479e8f560dae..47a156c16ce3e 100644 --- a/app/code/Magento/Backend/Block/System/Store/Delete/Form.php +++ b/app/code/Magento/Backend/Block/System/Store/Delete/Form.php @@ -5,6 +5,9 @@ */ namespace Magento\Backend\Block\System\Store\Delete; +use Magento\Backup\Helper\Data as BackupHelper; +use Magento\Framework\App\ObjectManager; + /** * Adminhtml cms block edit form * @@ -12,6 +15,25 @@ */ class Form extends \Magento\Backend\Block\Widget\Form\Generic { + /** + * @var BackupHelper + */ + private $backup; + + /** + * @inheritDoc + */ + public function __construct( + \Magento\Backend\Block\Template\Context $context, + \Magento\Framework\Registry $registry, + \Magento\Framework\Data\FormFactory $formFactory, + array $data = [], + ?BackupHelper $backup = null + ) { + parent::__construct($context, $registry, $formFactory, $data); + $this->backup = $backup ?? ObjectManager::getInstance()->get(BackupHelper::class); + } + /** * Init form * @@ -25,7 +47,7 @@ protected function _construct() } /** - * {@inheritdoc} + * @inheritDoc */ protected function _prepareForm() { @@ -45,6 +67,12 @@ protected function _prepareForm() $fieldset->addField('item_id', 'hidden', ['name' => 'item_id', 'value' => $dataObject->getId()]); + $backupOptions = ['0' => __('No')]; + $backupSelected = '0'; + if ($this->backup->isEnabled()) { + $backupOptions['1'] = __('Yes'); + $backupSelected = '1'; + } $fieldset->addField( 'create_backup', 'select', @@ -52,8 +80,8 @@ protected function _prepareForm() 'label' => __('Create DB Backup'), 'title' => __('Create DB Backup'), 'name' => 'create_backup', - 'options' => ['1' => __('Yes'), '0' => __('No')], - 'value' => '1' + 'options' => $backupOptions, + 'value' => $backupSelected ] ); diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php index 0beeb5168b6d1..a9be14b77b29c 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php @@ -14,6 +14,7 @@ * Store controller * * @author Magento Core Team <core@magentocommerce.com> + * @SuppressWarnings(PHPMD.AllPurposeAction) */ abstract class Store extends Action { @@ -86,6 +87,8 @@ protected function createPage() * Backup database * * @return bool + * + * @deprecated Backup module is to be removed. */ protected function _backupDatabase() { diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index.php b/app/code/Magento/Backup/Controller/Adminhtml/Index.php index dcafbc7370d2d..1878c7abc9dd5 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index.php @@ -5,12 +5,16 @@ */ namespace Magento\Backup\Controller\Adminhtml; +use Magento\Backup\Helper\Data as Helper; +use Magento\Framework\App\ObjectManager; + /** * Backup admin controller * * @author Magento Core Team <core@magentocommerce.com> * @api * @since 100.0.2 + * @SuppressWarnings(PHPMD.AllPurposeAction) */ abstract class Index extends \Magento\Backend\App\Action { @@ -48,6 +52,11 @@ abstract class Index extends \Magento\Backend\App\Action */ protected $maintenanceMode; + /** + * @var Helper + */ + private $helper; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry @@ -55,6 +64,7 @@ abstract class Index extends \Magento\Backend\App\Action * @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory * @param \Magento\Backup\Model\BackupFactory $backupModelFactory * @param \Magento\Framework\App\MaintenanceMode $maintenanceMode + * @param Helper|null $helper */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -62,13 +72,27 @@ public function __construct( \Magento\Framework\Backup\Factory $backupFactory, \Magento\Framework\App\Response\Http\FileFactory $fileFactory, \Magento\Backup\Model\BackupFactory $backupModelFactory, - \Magento\Framework\App\MaintenanceMode $maintenanceMode + \Magento\Framework\App\MaintenanceMode $maintenanceMode, + ?Helper $helper = null ) { $this->_coreRegistry = $coreRegistry; $this->_backupFactory = $backupFactory; $this->_fileFactory = $fileFactory; $this->_backupModelFactory = $backupModelFactory; $this->maintenanceMode = $maintenanceMode; + $this->helper = $helper ?? ObjectManager::getInstance()->get(Helper::class); parent::__construct($context); } + + /** + * @inheritDoc + */ + public function dispatch(\Magento\Framework\App\RequestInterface $request) + { + if (!$this->helper->isEnabled()) { + return $this->_redirect('*/*/disabled'); + } + + return parent::dispatch($request); + } } diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Disabled.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Disabled.php new file mode 100644 index 0000000000000..f6fe430ae0838 --- /dev/null +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Disabled.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Backup\Controller\Adminhtml\Index; + +use Magento\Backend\App\Action; +use Magento\Backend\App\Action\Context; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\View\Result\PageFactory; + +/** + * Inform that backup is disabled. + */ +class Disabled extends Action implements HttpGetActionInterface +{ + /** + * @see _isAllowed() + */ + const ADMIN_RESOURCE = 'Magento_Backend::backup'; + + /** + * @var PageFactory + */ + private $pageFactory; + + /** + * @param Context $context + * @param PageFactory $pageFactory + */ + public function __construct(Context $context, PageFactory $pageFactory) + { + parent::__construct($context); + $this->pageFactory = $pageFactory; + } + + /** + * @inheritDoc + */ + public function execute() + { + return $this->pageFactory->create(); + } +} diff --git a/app/code/Magento/Backup/Cron/SystemBackup.php b/app/code/Magento/Backup/Cron/SystemBackup.php index 750262ab1c14a..9502377a39d06 100644 --- a/app/code/Magento/Backup/Cron/SystemBackup.php +++ b/app/code/Magento/Backup/Cron/SystemBackup.php @@ -8,6 +8,9 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Store\Model\ScopeInterface; +/** + * Performs scheduled backup. + */ class SystemBackup { const XML_PATH_BACKUP_ENABLED = 'system/backup/enabled'; @@ -101,6 +104,10 @@ public function __construct( */ public function execute() { + if (!$this->_backupData->isEnabled()) { + return $this; + } + if (!$this->_scopeConfig->isSetFlag(self::XML_PATH_BACKUP_ENABLED, ScopeInterface::SCOPE_STORE)) { return $this; } diff --git a/app/code/Magento/Backup/Helper/Data.php b/app/code/Magento/Backup/Helper/Data.php index b0bc292ffe926..c6df6a7366852 100644 --- a/app/code/Magento/Backup/Helper/Data.php +++ b/app/code/Magento/Backup/Helper/Data.php @@ -3,6 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Backup\Helper; use Magento\Framework\App\Filesystem\DirectoryList; @@ -285,4 +288,14 @@ public function extractDataFromFilename($filename) return $result; } + + /** + * Is backup functionality enabled. + * + * @return bool + */ + public function isEnabled(): bool + { + return $this->scopeConfig->isSetFlag('system/backup/functionality_enabled'); + } } diff --git a/app/code/Magento/Backup/Model/Db.php b/app/code/Magento/Backup/Model/Db.php index 8fbd5da1c9842..bc458a0a8e4bf 100644 --- a/app/code/Magento/Backup/Model/Db.php +++ b/app/code/Magento/Backup/Model/Db.php @@ -5,11 +5,16 @@ */ namespace Magento\Backup\Model; +use Magento\Backup\Helper\Data as Helper; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Exception\RuntimeException; + /** * Database backup model * * @api * @since 100.0.2 + * @deprecated Backup module is to be removed. */ class Db implements \Magento\Framework\Backup\Db\BackupDbInterface { @@ -33,16 +38,24 @@ class Db implements \Magento\Framework\Backup\Db\BackupDbInterface */ protected $_resource = null; + /** + * @var Helper + */ + private $helper; + /** * @param \Magento\Backup\Model\ResourceModel\Db $resourceDb * @param \Magento\Framework\App\ResourceConnection $resource + * @param Helper|null $helper */ public function __construct( \Magento\Backup\Model\ResourceModel\Db $resourceDb, - \Magento\Framework\App\ResourceConnection $resource + \Magento\Framework\App\ResourceConnection $resource, + ?Helper $helper = null ) { $this->_resourceDb = $resourceDb; $this->_resource = $resource; + $this->helper = $helper ?? ObjectManager::getInstance()->get(Helper::class); } /** @@ -63,6 +76,8 @@ public function getResource() } /** + * Tables list. + * * @return array */ public function getTables() @@ -71,6 +86,8 @@ public function getTables() } /** + * Command to recreate given table. + * * @param string $tableName * @param bool $addDropIfExists * @return string @@ -81,6 +98,8 @@ public function getTableCreateScript($tableName, $addDropIfExists = false) } /** + * Generate table's data dump. + * * @param string $tableName * @return string */ @@ -90,6 +109,8 @@ public function getTableDataDump($tableName) } /** + * Header for dumps. + * * @return string */ public function getHeader() @@ -98,6 +119,8 @@ public function getHeader() } /** + * Footer for dumps. + * * @return string */ public function getFooter() @@ -106,6 +129,8 @@ public function getFooter() } /** + * Get backup SQL. + * * @return string */ public function renderSql() @@ -124,13 +149,14 @@ public function renderSql() } /** - * Create backup and stream write to adapter - * - * @param \Magento\Framework\Backup\Db\BackupInterface $backup - * @return $this + * @inheritDoc */ public function createBackup(\Magento\Framework\Backup\Db\BackupInterface $backup) { + if (!$this->helper->isEnabled()) { + throw new RuntimeException(__('Backup functionality is disabled')); + } + $backup->open(true); $this->getResource()->beginTransaction(); @@ -179,8 +205,6 @@ public function createBackup(\Magento\Framework\Backup\Db\BackupInterface $backu $this->getResource()->commitTransaction(); $backup->close(); - - return $this; } /** diff --git a/app/code/Magento/Backup/Test/Unit/Cron/SystemBackupTest.php b/app/code/Magento/Backup/Test/Unit/Cron/SystemBackupTest.php index b7dfb30c0a1b3..56a7ef42a0bc2 100644 --- a/app/code/Magento/Backup/Test/Unit/Cron/SystemBackupTest.php +++ b/app/code/Magento/Backup/Test/Unit/Cron/SystemBackupTest.php @@ -3,134 +3,44 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Backup\Test\Unit\Cron; +use Magento\Backup\Cron\SystemBackup; +use PHPUnit\Framework\TestCase; +use Magento\Backup\Helper\Data as Helper; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -class SystemBackupTest extends \PHPUnit\Framework\TestCase +class SystemBackupTest extends TestCase { /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager - */ - private $objectManager; - - /** - * @var \Magento\Backup\Cron\SystemBackup - */ - private $systemBackup; - - /** - * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $scopeConfigMock; - - /** - * @var \Magento\Backup\Helper\Data|\PHPUnit_Framework_MockObject_MockObject - */ - private $backupDataMock; - - /** - * @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject - */ - private $registryMock; - - /** - * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var Helper|\PHPUnit_Framework_MockObject_MockObject */ - private $loggerMock; + private $helperMock; /** - * Filesystem facade - * - * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject + * @var SystemBackup */ - private $filesystemMock; + private $cron; /** - * @var \Magento\Framework\Backup\Factory|\PHPUnit_Framework_MockObject_MockObject + * @inheritDoc */ - private $backupFactoryMock; - - /** - * @var \Magento\Framework\App\MaintenanceMode|\PHPUnit_Framework_MockObject_MockObject - */ - private $maintenanceModeMock; - - /** - * @var \Magento\Framework\Backup\Db|\PHPUnit_Framework_MockObject_MockObject - */ - private $backupDbMock; - - /** - * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $objectManagerMock; - protected function setUp() { - $this->objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) - ->getMock(); - $this->scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) - ->getMock(); - $this->backupDataMock = $this->getMockBuilder(\Magento\Backup\Helper\Data::class) - ->disableOriginalConstructor() - ->getMock(); - $this->registryMock = $this->getMockBuilder(\Magento\Framework\Registry::class) - ->disableOriginalConstructor() - ->getMock(); - $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) - ->getMock(); - $this->filesystemMock = $this->getMockBuilder(\Magento\Framework\Filesystem::class) - ->disableOriginalConstructor() - ->getMock(); - $this->backupFactoryMock = $this->getMockBuilder(\Magento\Framework\Backup\Factory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->maintenanceModeMock = $this->getMockBuilder(\Magento\Framework\App\MaintenanceMode::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->backupDbMock = $this->getMockBuilder(\Magento\Framework\Backup\Db::class) - ->disableOriginalConstructor() - ->getMock(); - $this->backupDbMock->expects($this->any())->method('setBackupExtension')->willReturnSelf(); - $this->backupDbMock->expects($this->any())->method('setTime')->willReturnSelf(); - $this->backupDbMock->expects($this->any())->method('setBackupsDir')->willReturnSelf(); - - $this->objectManager = new ObjectManager($this); - $this->systemBackup = $this->objectManager->getObject( - \Magento\Backup\Cron\SystemBackup::class, - [ - 'backupData' => $this->backupDataMock, - 'coreRegistry' => $this->registryMock, - 'logger' => $this->loggerMock, - 'scopeConfig' => $this->scopeConfigMock, - 'filesystem' => $this->filesystemMock, - 'backupFactory' => $this->backupFactoryMock, - 'maintenanceMode' => $this->maintenanceModeMock, - ] - ); + $objectManager = new ObjectManager($this); + $this->helperMock = $this->getMockBuilder(Helper::class)->disableOriginalConstructor()->getMock(); + $this->cron = $objectManager->getObject(SystemBackup::class, ['backupData' => $this->helperMock]); } /** - * @expectedException \Exception + * Test that cron doesn't do anything if backups are disabled. */ - public function testExecuteThrowsException() + public function testDisabled() { - $type = 'db'; - $this->scopeConfigMock->expects($this->any())->method('isSetFlag')->willReturn(true); - - $this->scopeConfigMock->expects($this->once())->method('getValue') - ->with('system/backup/type', 'store') - ->willReturn($type); - - $this->backupFactoryMock->expects($this->once())->method('create')->willReturn($this->backupDbMock); - - $this->backupDbMock->expects($this->once())->method('create')->willThrowException(new \Exception); - - $this->backupDataMock->expects($this->never())->method('getCreateSuccessMessageByType')->with($type); - $this->loggerMock->expects($this->never())->method('info'); - - $this->systemBackup->execute(); + $this->helperMock->expects($this->any())->method('isEnabled')->willReturn(false); + $this->cron->execute(); } } diff --git a/app/code/Magento/Backup/Test/Unit/Model/DbTest.php b/app/code/Magento/Backup/Test/Unit/Model/DbTest.php deleted file mode 100644 index 0cab5f0ad1e99..0000000000000 --- a/app/code/Magento/Backup/Test/Unit/Model/DbTest.php +++ /dev/null @@ -1,243 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Backup\Test\Unit\Model; - -use Magento\Backup\Model\Db; -use Magento\Backup\Model\ResourceModel\Db as DbResource; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Backup\Db\BackupInterface; -use Magento\Framework\DataObject; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; - -class DbTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var ObjectManager - */ - private $objectManager; - - /** - * @var Db - */ - private $dbModel; - - /** - * @var DbResource|\PHPUnit_Framework_MockObject_MockObject - */ - private $dbResourceMock; - - /** - * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject - */ - private $connectionResourceMock; - - protected function setUp() - { - $this->dbResourceMock = $this->getMockBuilder(DbResource::class) - ->disableOriginalConstructor() - ->getMock(); - $this->connectionResourceMock = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManager = new ObjectManager($this); - $this->dbModel = $this->objectManager->getObject( - Db::class, - [ - 'resourceDb' => $this->dbResourceMock, - 'resource' => $this->connectionResourceMock - ] - ); - } - - public function testGetResource() - { - self::assertEquals($this->dbResourceMock, $this->dbModel->getResource()); - } - - public function testGetTables() - { - $tables = []; - $this->dbResourceMock->expects($this->once()) - ->method('getTables') - ->willReturn($tables); - - self::assertEquals($tables, $this->dbModel->getTables()); - } - - public function testGetTableCreateScript() - { - $tableName = 'some_table'; - $script = 'script'; - $this->dbResourceMock->expects($this->once()) - ->method('getTableCreateScript') - ->with($tableName, false) - ->willReturn($script); - - self::assertEquals($script, $this->dbModel->getTableCreateScript($tableName, false)); - } - - public function testGetTableDataDump() - { - $tableName = 'some_table'; - $dump = 'dump'; - $this->dbResourceMock->expects($this->once()) - ->method('getTableDataDump') - ->with($tableName) - ->willReturn($dump); - - self::assertEquals($dump, $this->dbModel->getTableDataDump($tableName)); - } - - public function testGetHeader() - { - $header = 'header'; - $this->dbResourceMock->expects($this->once()) - ->method('getHeader') - ->willReturn($header); - - self::assertEquals($header, $this->dbModel->getHeader()); - } - - public function testGetFooter() - { - $footer = 'footer'; - $this->dbResourceMock->expects($this->once()) - ->method('getFooter') - ->willReturn($footer); - - self::assertEquals($footer, $this->dbModel->getFooter()); - } - - public function testRenderSql() - { - $header = 'header'; - $script = 'script'; - $tableName = 'some_table'; - $tables = [$tableName, $tableName]; - $dump = 'dump'; - $footer = 'footer'; - - $this->dbResourceMock->expects($this->once()) - ->method('getTables') - ->willReturn($tables); - $this->dbResourceMock->expects($this->once()) - ->method('getHeader') - ->willReturn($header); - $this->dbResourceMock->expects($this->exactly(2)) - ->method('getTableCreateScript') - ->with($tableName, true) - ->willReturn($script); - $this->dbResourceMock->expects($this->exactly(2)) - ->method('getTableDataDump') - ->with($tableName) - ->willReturn($dump); - $this->dbResourceMock->expects($this->once()) - ->method('getFooter') - ->willReturn($footer); - - self::assertEquals( - $header . $script . $dump . $script . $dump . $footer, - $this->dbModel->renderSql() - ); - } - - public function testCreateBackup() - { - /** @var BackupInterface|\PHPUnit_Framework_MockObject_MockObject $backupMock */ - $backupMock = $this->getMockBuilder(BackupInterface::class)->getMock(); - /** @var DataObject $tableStatus */ - $tableStatus = new DataObject(); - - $tableName = 'some_table'; - $tables = [$tableName]; - $header = 'header'; - $footer = 'footer'; - $dropSql = 'drop_sql'; - $createSql = 'create_sql'; - $beforeSql = 'before_sql'; - $afterSql = 'after_sql'; - $dataSql = 'data_sql'; - $foreignKeysSql = 'foreign_keys'; - $triggersSql = 'triggers_sql'; - $rowsCount = 2; - $dataLength = 1; - - $this->dbResourceMock->expects($this->once()) - ->method('beginTransaction'); - $this->dbResourceMock->expects($this->once()) - ->method('commitTransaction'); - $this->dbResourceMock->expects($this->once()) - ->method('getTables') - ->willReturn($tables); - $this->dbResourceMock->expects($this->once()) - ->method('getTableDropSql') - ->willReturn($dropSql); - $this->dbResourceMock->expects($this->once()) - ->method('getTableCreateSql') - ->with($tableName, false) - ->willReturn($createSql); - $this->dbResourceMock->expects($this->once()) - ->method('getTableDataBeforeSql') - ->with($tableName) - ->willReturn($beforeSql); - $this->dbResourceMock->expects($this->once()) - ->method('getTableDataAfterSql') - ->with($tableName) - ->willReturn($afterSql); - $this->dbResourceMock->expects($this->once()) - ->method('getTableDataSql') - ->with($tableName, $rowsCount, 0) - ->willReturn($dataSql); - $this->dbResourceMock->expects($this->once()) - ->method('getTableStatus') - ->with($tableName) - ->willReturn($tableStatus); - $this->dbResourceMock->expects($this->once()) - ->method('getTables') - ->willReturn($createSql); - $this->dbResourceMock->expects($this->once()) - ->method('getHeader') - ->willReturn($header); - $this->dbResourceMock->expects($this->once()) - ->method('getTableHeader') - ->willReturn($header); - $this->dbResourceMock->expects($this->once()) - ->method('getFooter') - ->willReturn($footer); - $this->dbResourceMock->expects($this->once()) - ->method('getTableForeignKeysSql') - ->willReturn($foreignKeysSql); - $this->dbResourceMock->expects($this->once()) - ->method('getTableTriggersSql') - ->willReturn($triggersSql); - $backupMock->expects($this->once()) - ->method('open'); - $backupMock->expects($this->once()) - ->method('close'); - - $tableStatus->setRows($rowsCount); - $tableStatus->setDataLength($dataLength); - - $backupMock->expects($this->any()) - ->method('write') - ->withConsecutive( - [$this->equalTo($header)], - [$this->equalTo($header . $dropSql . "\n")], - [$this->equalTo($createSql . "\n")], - [$this->equalTo($beforeSql)], - [$this->equalTo($dataSql)], - [$this->equalTo($afterSql)], - [$this->equalTo($foreignKeysSql)], - [$this->equalTo($triggersSql)], - [$this->equalTo($footer)] - ); - - $this->dbModel->createBackup($backupMock); - } -} diff --git a/app/code/Magento/Backup/etc/adminhtml/system.xml b/app/code/Magento/Backup/etc/adminhtml/system.xml index 4028452d04439..90f6fa861b40f 100644 --- a/app/code/Magento/Backup/etc/adminhtml/system.xml +++ b/app/code/Magento/Backup/etc/adminhtml/system.xml @@ -9,13 +9,21 @@ <system> <section id="system"> <group id="backup" translate="label" type="text" sortOrder="500" showInDefault="1" showInWebsite="0" showInStore="0"> - <label>Scheduled Backup Settings</label> + <label>Backup Settings</label> + <field id="functionality_enabled" translate="label" type="select" sortOrder="5" showInDefault="1" showInWebsite="0" showInStore="0"> + <label>Enable Backup</label> + <comment>Disabled by default for security reasons</comment> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + </field> <field id="enabled" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Enable Scheduled Backup</label> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <depends> + <field id="functionality_enabled">1</field> + </depends> </field> <field id="type" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0"> - <label>Backup Type</label> + <label>Scheduled Backup Type</label> <depends> <field id="enabled">1</field> </depends> diff --git a/app/code/Magento/Backup/etc/config.xml b/app/code/Magento/Backup/etc/config.xml new file mode 100644 index 0000000000000..fb0808983b9c8 --- /dev/null +++ b/app/code/Magento/Backup/etc/config.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd"> + <default> + <system> + <backup> + <functionality_enabled>0</functionality_enabled> + </backup> + </system> + </default> +</config> diff --git a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_disabled.xml b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_disabled.xml new file mode 100644 index 0000000000000..3470f528e5ceb --- /dev/null +++ b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_disabled.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <head> + <title>Backup functionality is disabled + + + + + + + diff --git a/app/code/Magento/Backup/view/adminhtml/templates/backup/disabled.phtml b/app/code/Magento/Backup/view/adminhtml/templates/backup/disabled.phtml new file mode 100644 index 0000000000000..a5308dce5cc52 --- /dev/null +++ b/app/code/Magento/Backup/view/adminhtml/templates/backup/disabled.phtml @@ -0,0 +1,7 @@ + +

    Backup functionality is currently disabled. Please use other means for backups

    diff --git a/dev/tests/functional/tests/app/Magento/Backup/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Backup/Test/Repository/ConfigData.xml new file mode 100644 index 0000000000000..c8b19aa2bd32b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backup/Test/Repository/ConfigData.xml @@ -0,0 +1,24 @@ + + + + + + + Yes + 1 + + + + + No + 0 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml deleted file mode 100644 index 0c024f0e3f5aa..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - System > Backups - Backups - - - - diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php index e867ebe399784..c1fe9ca45972d 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php @@ -12,6 +12,7 @@ use Magento\Backup\Test\Page\Adminhtml\BackupIndex; use Magento\Store\Test\Fixture\Store; use Magento\Mtf\TestCase\Injectable; +use Magento\Config\Test\TestStep\SetupConfigurationStep; /** * Test Creation for DeleteStoreEntity @@ -100,7 +101,15 @@ public function test(Store $store, $createBackup) { // Preconditions: $store->persist(); - $this->backupIndex->open()->getBackupGrid()->massaction([], 'Delete', true, 'Select All'); + /** @var SetupConfigurationStep $enableBackupsStep */ + $enableBackupsStep = $this->objectManager->create( + SetupConfigurationStep::class, + ['configData' => 'enable_backups_functionality'] + ); + $enableBackupsStep->run(); + $this->backupIndex->open() + ->getBackupGrid() + ->massaction([], 'Delete', true, 'Select All'); // Steps: $this->storeIndex->open(); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php index cd37576443cdb..c332b83a22deb 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php @@ -12,6 +12,7 @@ use Magento\Backup\Test\Page\Adminhtml\BackupIndex; use Magento\Store\Test\Fixture\StoreGroup; use Magento\Mtf\TestCase\Injectable; +use Magento\Config\Test\TestStep\SetupConfigurationStep; /** * Delete StoreGroup (Store Management) @@ -101,7 +102,15 @@ public function test(StoreGroup $storeGroup, $createBackup) { //Preconditions $storeGroup->persist(); - $this->backupIndex->open()->getBackupGrid()->massaction([], 'Delete', true, 'Select All'); + /** @var SetupConfigurationStep $enableBackupsStep */ + $enableBackupsStep = $this->objectManager->create( + SetupConfigurationStep::class, + ['configData' => 'enable_backups_functionality'] + ); + $enableBackupsStep->run(); + $this->backupIndex->open() + ->getBackupGrid() + ->massaction([], 'Delete', true, 'Select All'); //Steps $this->storeIndex->open(); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php index 2431cb3e065d2..22259a30b1538 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php @@ -12,6 +12,7 @@ use Magento\Backup\Test\Page\Adminhtml\BackupIndex; use Magento\Store\Test\Fixture\Website; use Magento\Mtf\TestCase\Injectable; +use Magento\Config\Test\TestStep\SetupConfigurationStep; /** * Delete Website (Store Management) @@ -102,7 +103,15 @@ public function test(Website $website, $createBackup) { //Preconditions $website->persist(); - $this->backupIndex->open()->getBackupGrid()->massaction([], 'Delete', true, 'Select All'); + /** @var SetupConfigurationStep $enableBackupsStep */ + $enableBackupsStep = $this->objectManager->create( + SetupConfigurationStep::class, + ['configData' => 'enable_backups_functionality'] + ); + $enableBackupsStep->run(); + $this->backupIndex->open() + ->getBackupGrid() + ->massaction([], 'Delete', true, 'Select All'); //Steps $this->storeIndex->open(); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php index 155ed21064bcf..03486f337d74f 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php @@ -10,10 +10,12 @@ use Magento\Backend\Test\Page\Adminhtml\DeleteWebsite; use Magento\Backend\Test\Page\Adminhtml\StoreIndex; use Magento\Backup\Test\Page\Adminhtml\BackupIndex; +use Magento\Config\Test\TestStep\SetupConfigurationStep; use Magento\Store\Test\Fixture\Store; use Magento\Mtf\TestStep\TestStepInterface; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\Fixture\FixtureInterface; +use Magento\Mtf\TestStep\TestStepFactory; /** * Test Step for DeleteWebsitesEntity. @@ -60,6 +62,11 @@ class DeleteWebsitesEntityStep implements TestStepInterface */ private $createBackup; + /** + * @var TestStepFactory + */ + private $stepFactory; + /** * Prepare pages for test. * @@ -69,6 +76,7 @@ class DeleteWebsitesEntityStep implements TestStepInterface * @param DeleteWebsite $deleteWebsite * @param FixtureFactory $fixtureFactory * @param FixtureInterface $item + * @param TestStepFactory $testStepFactory * @param string $createBackup */ public function __construct( @@ -78,6 +86,7 @@ public function __construct( DeleteWebsite $deleteWebsite, FixtureFactory $fixtureFactory, FixtureInterface $item, + TestStepFactory $testStepFactory, $createBackup = 'No' ) { $this->storeIndex = $storeIndex; @@ -87,6 +96,7 @@ public function __construct( $this->item = $item; $this->createBackup = $createBackup; $this->fixtureFactory = $fixtureFactory; + $this->stepFactory = $testStepFactory; } /** @@ -96,6 +106,12 @@ public function __construct( */ public function run() { + /** @var SetupConfigurationStep $enableBackupsStep */ + $enableBackupsStep = $this->stepFactory->create( + SetupConfigurationStep::class, + ['configData' => 'enable_backups_functionality'] + ); + $enableBackupsStep->run(); $this->backupIndex->open()->getBackupGrid()->massaction([], 'Delete', true, 'Select All'); $this->storeIndex->open(); $websiteNames = $this->item->getWebsiteIds(); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Backup/DbTest.php b/dev/tests/integration/testsuite/Magento/Framework/Backup/DbTest.php index 9d149eceb4542..3ee68b1012c4e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Backup/DbTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Backup/DbTest.php @@ -34,6 +34,7 @@ public static function setUpBeforeClass() /** * Test db backup includes triggers. * + * @magentoConfigFixture default/system/backup/functionality_enabled 1 * @magentoDataFixture Magento/Framework/Backup/_files/trigger.php * @magentoDbIsolation disabled */ diff --git a/lib/internal/Magento/Framework/Backup/BackupInterface.php b/lib/internal/Magento/Framework/Backup/BackupInterface.php index 3d054bdbd1a9c..16aada9689c11 100644 --- a/lib/internal/Magento/Framework/Backup/BackupInterface.php +++ b/lib/internal/Magento/Framework/Backup/BackupInterface.php @@ -13,6 +13,8 @@ /** * @api + * + * @deprecated Backups should be done using other means. */ interface BackupInterface { diff --git a/lib/internal/Magento/Framework/Backup/Db/BackupDbInterface.php b/lib/internal/Magento/Framework/Backup/Db/BackupDbInterface.php index 13e3c562bb527..a019ccac06b66 100644 --- a/lib/internal/Magento/Framework/Backup/Db/BackupDbInterface.php +++ b/lib/internal/Magento/Framework/Backup/Db/BackupDbInterface.php @@ -7,6 +7,8 @@ /** * @api + * + * @deprecated Backups should be done using other means. */ interface BackupDbInterface { diff --git a/lib/internal/Magento/Framework/Backup/Db/BackupInterface.php b/lib/internal/Magento/Framework/Backup/Db/BackupInterface.php index f7459f629cb4a..ae5879290eb20 100644 --- a/lib/internal/Magento/Framework/Backup/Db/BackupInterface.php +++ b/lib/internal/Magento/Framework/Backup/Db/BackupInterface.php @@ -7,6 +7,8 @@ /** * @api + * + * @deprecated Backups should be done using other means. */ interface BackupInterface { From 5f1b4014093e062169dd9597752eac1c970898e2 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov Date: Mon, 8 Oct 2018 14:10:04 +0300 Subject: [PATCH 0172/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Block/DataProviders/ImageUploadConfig.php | 37 +++++++++++++++++++ .../Magento/Backend/Block/Media/Uploader.php | 10 ----- .../adminhtml/templates/media/uploader.phtml | 2 +- .../Product/Helper/Form/Gallery/Content.php | 20 ++++++++-- .../layout/cms_wysiwyg_images_index.xml | 6 ++- .../templates/browser/content/uploader.phtml | 6 +-- 6 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php diff --git a/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php b/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php new file mode 100644 index 0000000000000..1ba3daf35d2cf --- /dev/null +++ b/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php @@ -0,0 +1,37 @@ +imageUploadConfig = $imageUploadConfig; + } + + /** + * Get image resize configuration + * + * @return int + */ + public function getIsResizeEnabled(): int + { + return (int)$this->imageUploadConfig->isResizeEnabled(); + } +} diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php index 22e9197418e4c..c332c91b54b27 100644 --- a/app/code/Magento/Backend/Block/Media/Uploader.php +++ b/app/code/Magento/Backend/Block/Media/Uploader.php @@ -127,16 +127,6 @@ public function getImageUploadMaxHeight() return $this->imageUploadConfig->getMaxHeight(); } - /** - * Get image resize configuration - * - * @return int - */ - public function getIsResizeEnabled(): int - { - return (int)$this->imageUploadConfig->isResizeEnabled(); - } - /** * Prepares layout and set element renderer * diff --git a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml index d6e97cf4d58e3..4d9ba6a8c4bad 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml @@ -15,7 +15,7 @@ "maxFileSize": getFileSizeService()->getMaxFileSize() ?>, "maxWidth": getImageUploadMaxWidth() ?>, "maxHeight": getImageUploadMaxHeight() ?>, - "isResizeEnabled": getIsResizeEnabled() ?> + "isResizeEnabled": getImageUploadConfigData()->getIsResizeEnabled() ?> } }' > diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php index e1208e25cc7c8..d9e343fd2b3f0 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php @@ -13,11 +13,12 @@ */ namespace Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Gallery; +use Magento\Framework\App\ObjectManager; use Magento\Backend\Block\Media\Uploader; use Magento\Framework\View\Element\AbstractBlock; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\FileSystemException; - +use Magento\Backend\Block\DataProviders\ImageUploadConfig as ImageUploadConfigDataProvider; /** * Block for gallery content. */ @@ -43,21 +44,30 @@ class Content extends \Magento\Backend\Block\Widget */ private $imageHelper; + /** + * @var ImageUploadConfigDataProvider + */ + private $imageUploadConfigDataProvider; + /** * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder * @param \Magento\Catalog\Model\Product\Media\Config $mediaConfig * @param array $data + * @param ImageUploadConfigDataProvider $imageUploadConfigDataProvider */ public function __construct( \Magento\Backend\Block\Template\Context $context, \Magento\Framework\Json\EncoderInterface $jsonEncoder, \Magento\Catalog\Model\Product\Media\Config $mediaConfig, - array $data = [] + array $data = [], + ImageUploadConfigDataProvider $imageUploadConfigDataProvider = null ) { $this->_jsonEncoder = $jsonEncoder; $this->_mediaConfig = $mediaConfig; parent::__construct($context, $data); + $this->imageUploadConfigDataProvider = $imageUploadConfigDataProvider + ?: ObjectManager::getInstance()->get(ImageUploadConfigDataProvider::class); } /** @@ -67,7 +77,11 @@ public function __construct( */ protected function _prepareLayout() { - $this->addChild('uploader', \Magento\Backend\Block\Media\Uploader::class); + $this->addChild( + 'uploader', + \Magento\Backend\Block\Media\Uploader::class, + ['image_upload_config_data' => $this->imageUploadConfigDataProvider] + ); $this->getUploader()->getConfig()->setUrl( $this->_urlBuilder->addSessionParam()->getUrl('catalog/product_gallery/upload') diff --git a/app/code/Magento/Cms/view/adminhtml/layout/cms_wysiwyg_images_index.xml b/app/code/Magento/Cms/view/adminhtml/layout/cms_wysiwyg_images_index.xml index 1bc8828ef6c8e..6703b6c277123 100644 --- a/app/code/Magento/Cms/view/adminhtml/layout/cms_wysiwyg_images_index.xml +++ b/app/code/Magento/Cms/view/adminhtml/layout/cms_wysiwyg_images_index.xml @@ -9,7 +9,11 @@ - + + + Magento\Backend\Block\DataProviders\ImageUploadConfig + + diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml index b1824f639c940..c6810f774238c 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml @@ -17,11 +17,11 @@ foreach ($filters as $media_type) { }, $media_type['files'])); } -$resizeConfig = ($block->getIsResizeEnabled()) +$resizeConfig = ($block->getImageUploadConfigData()->getIsResizeEnabled()) ? "{action: 'resize', maxWidth: " - . $block->getImageUploadMaxWidth() + . $block->escapeHtml($block->getImageUploadMaxWidth()) . ", maxHeight: " - . $block->getImageUploadMaxHeight() + . $block->escapeHtml($block->getImageUploadMaxHeight()) . "}" : "{action: 'resize'}"; ?> From d921849d060864994249f387487d743dce85fc06 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak Date: Mon, 8 Oct 2018 14:12:59 +0300 Subject: [PATCH 0173/1158] MAGETWO-91517: Cancel and Return link removes billing and shipping address - Fix statics. --- .../view/frontend/web/js/model/checkout-data-resolver.js | 1 + .../Checkout/view/frontend/web/js/view/form/element/email.js | 1 + 2 files changed, 2 insertions(+) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js index 4abb4c4d61700..cd4c59df51187 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js @@ -75,6 +75,7 @@ define([ } newCustomerShippingAddress = checkoutData.getNewCustomerShippingAddress(); + if (newCustomerShippingAddress) { createShippingAddress(newCustomerShippingAddress); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js index 37a785e292365..4d883fb1373bd 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js @@ -27,6 +27,7 @@ define([ } validatedEmail = checkoutData.getValidatedEmailValue(); + if (validatedEmail && !customer.isLoggedIn()) { quote.guestEmail = validatedEmail; } From eb2dd92bfab57e45a50b60f7d29adb80bff27c38 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov Date: Mon, 8 Oct 2018 19:19:25 +0300 Subject: [PATCH 0174/1158] MAGETWO-91651: Navigation Menu problem on Mobile theme - Added scroll to top menu items --- lib/web/mage/menu.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index b8000640506f1..7096c4ecb7d6d 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -439,6 +439,7 @@ define([ event.preventDefault(); target = $(event.target).closest('.ui-menu-item'); + target.get(0).scrollIntoView(); if (!target.hasClass('level-top') || !target.has('.ui-menu').length) { window.location.href = target.find('> a').attr('href'); From 02bdadd38cd023840ed85cca43b6091c3457d94a Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina Date: Tue, 9 Oct 2018 11:33:27 +0300 Subject: [PATCH 0175/1158] MAGETWO-91517: Cancel and Return link removes billing and shipping address - Fix statics. --- .../view/frontend/web/js/model/checkout-data-resolver.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js index cd4c59df51187..1c2438889c170 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js @@ -214,6 +214,7 @@ define([ selectedBillingAddress = checkoutData.getSelectedBillingAddress(); newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress(); + if (selectedBillingAddress) { if (selectedBillingAddress == 'new-customer-address' && newCustomerBillingAddressData) { //eslint-disable-line selectBillingAddress(createBillingAddress(newCustomerBillingAddressData)); From e819fc98e142b3f93a45cad3ae6ee061209265a5 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov Date: Tue, 9 Oct 2018 13:00:35 +0300 Subject: [PATCH 0176/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Test/AdminSimpleProductImagesTest.xml | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml index 69931395a35d5..b10c8e5ad54a0 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml @@ -87,10 +87,9 @@ - - + @@ -115,8 +114,7 @@ - - + @@ -136,9 +134,9 @@ - - - + + + @@ -154,16 +152,16 @@ - + - + - +
    From 21c32ebe67d3d02a3b2333ab4c925a31bead45cf Mon Sep 17 00:00:00 2001 From: David Grigoryan Date: Wed, 3 Oct 2018 10:57:29 +0400 Subject: [PATCH 0177/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Add automated test --- .../Test/Mftf/Data/AuthorizenetData.xml | 95 +++++++++++++++++++ .../Mftf/Metadata/authorize-config-meta.xml | 79 +++++++++++++++ .../AuthorizenetConfiguraionSection.xml | 19 ++++ .../AuthorizenetCreditCardInformationTest.xml | 81 ++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml b/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml new file mode 100644 index 0000000000000..c4f59ba03bf22 --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml @@ -0,0 +1,95 @@ + + + + + + Active + LoginId + TransactionKey + TransMD5 + TestMode + CVVVerification + CGI_UTL + CGI_URL_TD + Debug + + + 1 + + + 4By5Q8m6 + + + 9pygB4X4n783TJbw + + + Md5Hash + + + 0 + + + 1 + + + https://test.authorize.net/gateway/transact.dll + + + https://apitest.authorize.net/xml/v1/request.api + + + 1 + + + + DefaultActive + DefaultTransactionKey + DefaultTransMD5 + DefaultTestMode + DefaultCVVVerification + DefaultCGI_UTL + DefaultCGI_URL_TD + DefaultDebugMode + + + 0 + + + 0 + + + + + + + + + + + + 1 + + + 0 + + + https://secure.authorize.net/gateway/transact.dll + + + https://api2.authorize.net/xml/v1/request.api + + + + DisableConfig + + + + 0 + + diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml b/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml new file mode 100644 index 0000000000000..ca9bbdad00870 --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml @@ -0,0 +1,79 @@ + + + + + + + + + integer + + + string + + + string + + + string + + + string + + + string + + + string + + + string + + + string + + + + + + + + + + + + + integer + + + + + integer + + + + + integer + + + + + integer + + + + + integer + + + + + + + diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml b/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml new file mode 100644 index 0000000000000..5d4f6c3f9819a --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml @@ -0,0 +1,19 @@ + + + +
    + + + + + + + +
    +
    diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml b/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml new file mode 100644 index 0000000000000..b5d0b6079bb8b --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml @@ -0,0 +1,81 @@ + + + + + + + + + + <description value="Checking credit card information of Authorize.net Direct Post"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-91526"/> + <group value="Authorizenet"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> + <createData stepKey="setConfig" entity="AuthorizenetConfig"/> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createCategory" stepKey="deleteProduct"/> + <deleteData createDataKey="createProduct" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <createData stepKey="setDefaultConfig" entity="AuthorizenetDefaultConfig"/> + <createData stepKey="DisableConfigValues" entity="DisableAuthorizenetConfig"/> + </after> + <!--Create new order--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="CreateNewOrder"> + <argument name="customer" value="Simple_US_Customer_NY"/> + </actionGroup> + <!--Add product to order--> + <click selector="{{OrdersGridSection.addProducts}}" stepKey="clickToAddProduct"/> + <waitForPageLoad stepKey="waitForProductsOpened"/> + <click selector="{{OrdersGridSection.selectProduct($$createProduct.name$$)}}" stepKey="selectProduct"/> + <click stepKey="addProductsToOrder" selector="{{OrdersGridSection.addProductsToOrder}}"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <!--Select shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShipping"/> + <!--Fill Card data and submit order--> + <click selector="{{AuthorizenetConfigurationSection.paymentMethod}}" stepKey="clickToSetPaymentMethod"/> + <selectOption selector="{{AuthorizenetConfigurationSection.cardType}}" userInput="Visa" stepKey="SelectCreditCard"/> + <fillField selector="{{AuthorizenetConfigurationSection.cardNumber}}" userInput="4111111111111111" stepKey="fillCardNumber"/> + <selectOption selector="{{AuthorizenetConfigurationSection.month}}" userInput="01 - January" stepKey="SelectMonth"/> + <click selector="{{AuthorizenetConfigurationSection.year}}" stepKey="clickYear"/> + <waitForElementVisible selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="waitForDropDownMenuAppeared"/> + <click selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="selectYear"/> + <fillField selector="{{AuthorizenetConfigurationSection.verificationNumber}}" userInput="123" stepKey="fillVerificationNumber"/> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="SubmitOrder"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <!--Get order ID and open order page--> + <see userinput="You created the order." stepKey="verifyOrderCreated"/> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$getOrderId"/> + </actionGroup> + <click selector="{{AdminDataGridTableSection.rowViewAction('1')}}" stepKey="clickCreatedOrderInGrid"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <!--Verify required data--> + <see userinput="Credit Card Direct Post (Authorize.net)" stepKey="checkPaymentMethod"/> + <see userinput="Credit Card Type: MasterCard" stepKey="checkCardType"/> + <see userinput="Credit Card Number: XXXX1111" stepKey="checkCardCode"/> + <see userinput="AVS Response Code:" stepKey="checkAVSResponseCode"/> + <see userinput="Processor Authentication Code:" stepKey="checkProcessorAuthorizationCode"/> + <see userinput="Processor Response Text:" stepKey="checkProcessorResponseText"/> + <see userinput="CVV2 Response Code:" stepKey="checkCVVResponseCode"/> + <see userinput="The order was placed using USD." stepKey="checkCurrency"/> + </test> +</tests> From b4181a0795e56c9954f6c03454af5e765727c597 Mon Sep 17 00:00:00 2001 From: Nick Shatilo <shatilo.nick@gmail.com> Date: Thu, 4 Oct 2018 12:29:02 +0300 Subject: [PATCH 0178/1158] fix(Webapi Xml Renderer - 18361): removed the not needed ampersand replacement, covered by tests --- .../Magento/Framework/Webapi/Rest/Response/Renderer/Xml.php | 4 ++-- .../Webapi/Test/Unit/Rest/Response/Renderer/XmlTest.php | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Webapi/Rest/Response/Renderer/Xml.php b/lib/internal/Magento/Framework/Webapi/Rest/Response/Renderer/Xml.php index b4cfc61611a93..62b0d30b294b6 100644 --- a/lib/internal/Magento/Framework/Webapi/Rest/Response/Renderer/Xml.php +++ b/lib/internal/Magento/Framework/Webapi/Rest/Response/Renderer/Xml.php @@ -111,8 +111,7 @@ protected function _formatValue($value) /** Without the following transformation boolean values are rendered incorrectly */ $value = $value ? 'true' : 'false'; } - $replacementMap = ['&' => '&']; - return str_replace(array_keys($replacementMap), array_values($replacementMap), $value); + return (string) $value; } /** @@ -166,3 +165,4 @@ protected function _prepareKey($key) return $key; } } + diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/Renderer/XmlTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/Renderer/XmlTest.php index 396fbcdb1978b..71fb41491cc74 100644 --- a/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/Renderer/XmlTest.php +++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/Renderer/XmlTest.php @@ -76,6 +76,11 @@ public function providerXmlRender() '<?xml version="1.0"?><response><item_7key>value</item_7key></response>', 'Invalid XML render with numeric symbol in data index.' ], + [ + ['key' => 'test & foo'], + '<?xml version="1.0"?><response><key>test & foo</key></response>', + 'Invalid XML render with ampersand symbol in data index.' + ], [ ['.key' => 'value'], '<?xml version="1.0"?><response><item_key>value</item_key></response>', From 3370c8110ef6c479a1886722c447593b0437340a Mon Sep 17 00:00:00 2001 From: Karen_Mkhitaryan <Karen_Mkhitaryan@epam.com> Date: Tue, 9 Oct 2018 17:28:12 +0400 Subject: [PATCH 0179/1158] MAGETWO-91628: Bundle product price doubled when switching currency - Add minor changes in test --- .../Mftf/Test/CurrencyChangingBundleProductInCartTest.xml | 6 ++++++ .../Test/Mftf/Section/CurrencySetupSection.xml | 1 + 2 files changed, 7 insertions(+) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml index b7e716dc15ece..ded8bb3c83337 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/CurrencyChangingBundleProductInCartTest.xml @@ -28,12 +28,16 @@ <argument name="product" value="BundleProduct"/> </actionGroup> <actionGroup ref="AdminClearFiltersActionGroup" stepKey="ClearFiltersAfter"/> + <waitForPageLoad stepKey="waitForClearFilter"/> <!--Clear Configs--> <amOnPage url="{{AdminLoginPage.url}}" stepKey="navigateToAdmin"/> <waitForPageLoad stepKey="waitForAdminLoginPageLoad"/> <amOnPage url="{{ConfigCurrencySetupPage.url}}" stepKey="navigateToConfigCurrencySetupPage"/> <waitForPageLoad stepKey="waitForConfigCurrencySetupPageForUnselectEuroCurrency"/> <unselectOption selector="{{CurrencySetupSection.allowCurrencies}}" userInput="Euro" stepKey="unselectEuro"/> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> + <click selector="{{CurrencySetupSection.currencyOptions}}" stepKey="closeOptions"/> + <waitForPageLoad stepKey="waitForCloseOptions"/> <click stepKey="saveUnselectedConfigs" selector="{{AdminConfigSection.saveButton}}"/> <amOnPage url="{{AdminLogoutPage.url}}" stepKey="logout"/> <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> @@ -57,6 +61,8 @@ <actionGroup ref="saveProductForm" stepKey="saveProduct"/> <amOnPage url="{{ConfigCurrencySetupPage.url}}" stepKey="navigateToConfigCurrencySetupPage"/> <waitForPageLoad stepKey="waitForConfigCurrencySetupPage"/> + <conditionalClick selector="{{CurrencySetupSection.currencyOptions}}" dependentSelector="{{CurrencySetupSection.allowCurrencies}}" visible="false" stepKey="openOptions"/> + <waitForPageLoad stepKey="waitForOptions"/> <selectOption selector="{{CurrencySetupSection.allowCurrencies}}" parameterArray="['Euro', 'US Dollar']" stepKey="selectCurrencies"/> <click stepKey="saveConfigs" selector="{{AdminConfigSection.saveButton}}"/> <!-- Go to storefront BundleProduct --> diff --git a/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml b/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml index 16101409ad7e8..20fcd1e89360c 100644 --- a/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml +++ b/app/code/Magento/CurrencySymbol/Test/Mftf/Section/CurrencySetupSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="CurrencySetupSection"> <element name="allowCurrencies" type="select" selector="#currency_options_allow"/> + <element name="currencyOptions" type="select" selector="#currency_options-head"/> </section> </sections> \ No newline at end of file From 2850e6ee21634c9251125cfca82fb83b600e29eb Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 9 Oct 2018 16:40:16 +0300 Subject: [PATCH 0180/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Block/DataProviders/ImageUploadConfig.php | 3 + .../Magento/Backend/Block/Media/Uploader.php | 11 +++- .../Product/Helper/Form/Gallery/Content.php | 1 + app/code/Magento/Catalog/Helper/Image.php | 6 ++ .../Magento/Catalog/Model/Product/Image.php | 58 +++++++++++++++++-- .../Model/Product/Image/ParamsBuilder.php | 7 +++ 6 files changed, 81 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php b/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php index 1ba3daf35d2cf..6ec40cfa0b2d4 100644 --- a/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php +++ b/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php @@ -20,6 +20,9 @@ class ImageUploadConfig implements ArgumentInterface */ private $imageUploadConfig; + /** + * @param ImageUploadConfigInterface $imageUploadConfig + */ public function __construct(ImageUploadConfigInterface $imageUploadConfig) { $this->imageUploadConfig = $imageUploadConfig; diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php index c332c91b54b27..941d6f37737fe 100644 --- a/app/code/Magento/Backend/Block/Media/Uploader.php +++ b/app/code/Magento/Backend/Block/Media/Uploader.php @@ -44,6 +44,13 @@ class Uploader extends \Magento\Backend\Block\Widget */ private $imageUploadConfig; + /** + * @var UploadConfigInterface + * @deprecated + * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface + */ + private $imageConfig; + /** * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Framework\File\Size $fileSize @@ -58,10 +65,12 @@ public function __construct( array $data = [], Json $jsonEncoder = null, UploadConfigInterface $imageConfig = null, - ImageUploadConfigInterface $imageUploadConfig = null + ImageUploadConfigInterface $imageUploadConfig = null ) { $this->_fileSizeService = $fileSize; $this->jsonEncoder = $jsonEncoder ?: ObjectManager::getInstance()->get(Json::class); + $this->imageConfig = $imageConfig + ?: ObjectManager::getInstance()->get(UploadConfigInterface::class); $this->imageUploadConfig = $imageUploadConfig ?: ObjectManager::getInstance()->get(ImageUploadConfigInterface::class); parent::__construct($context, $data); diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php index d9e343fd2b3f0..063503682f4db 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php @@ -19,6 +19,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\FileSystemException; use Magento\Backend\Block\DataProviders\ImageUploadConfig as ImageUploadConfigDataProvider; + /** * Block for gallery content. */ diff --git a/app/code/Magento/Catalog/Helper/Image.php b/app/code/Magento/Catalog/Helper/Image.php index 74153267f41d6..4a12bf7093943 100644 --- a/app/code/Magento/Catalog/Helper/Image.php +++ b/app/code/Magento/Catalog/Helper/Image.php @@ -407,6 +407,7 @@ public function rotate($angle) /** * Add watermark to image + * * size param in format 100x200 * * @param string $fileName @@ -534,6 +535,8 @@ public function getUrl() } /** + * Save changes + * * @return $this */ public function save() @@ -554,6 +557,8 @@ public function getResizedImageInfo() } /** + * Getter for placeholder url + * * @param null|string $placeholder * @return string */ @@ -656,6 +661,7 @@ protected function getWatermarkPosition() /** * Set watermark size + * * param size in format 100x200 * * @param string $size diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php index 564b817fc167e..8ad4e89d7b480 100644 --- a/app/code/Magento/Catalog/Model/Product/Image.php +++ b/app/code/Magento/Catalog/Model/Product/Image.php @@ -15,6 +15,8 @@ use Magento\Catalog\Model\Product\Image\ParamsBuilder; /** + * Image operations + * * @method string getFile() * @method string getLabel() * @method string getPosition() @@ -209,16 +211,16 @@ class Image extends \Magento\Framework\Model\AbstractModel * @param \Magento\Framework\Image\Factory $imageFactory * @param \Magento\Framework\View\Asset\Repository $assetRepo * @param \Magento\Framework\View\FileSystem $viewFileSystem + * @param ImageFactory $viewAssetImageFactory + * @param PlaceholderFactory $viewAssetPlaceholderFactory * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data - * @param ImageFactory|null $viewAssetImageFactory - * @param PlaceholderFactory|null $viewAssetPlaceholderFactory - * @param SerializerInterface|null $serializer + * @param SerializerInterface $serializer * @param ParamsBuilder $paramsBuilder * @SuppressWarnings(PHPMD.ExcessiveParameterList) - * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.UnusedLocalVariable)1 */ public function __construct( \Magento\Framework\Model\Context $context, @@ -255,6 +257,8 @@ public function __construct( } /** + * Set image width property + * * @param int $width * @return $this */ @@ -265,6 +269,8 @@ public function setWidth($width) } /** + * Get image width property + * * @return int */ public function getWidth() @@ -273,6 +279,8 @@ public function getWidth() } /** + * Set image height property + * * @param int $height * @return $this */ @@ -283,6 +291,8 @@ public function setHeight($height) } /** + * Get image height property + * * @return int */ public function getHeight() @@ -316,6 +326,8 @@ public function getQuality() } /** + * Set _keepAspectRatio property + * * @param bool $keep * @return $this */ @@ -326,6 +338,8 @@ public function setKeepAspectRatio($keep) } /** + * Set _keepFrame property + * * @param bool $keep * @return $this */ @@ -336,6 +350,8 @@ public function setKeepFrame($keep) } /** + * Set _keepTransparency + * * @param bool $keep * @return $this */ @@ -346,6 +362,8 @@ public function setKeepTransparency($keep) } /** + * Set _constrainOnly + * * @param bool $flag * @return $this */ @@ -356,6 +374,8 @@ public function setConstrainOnly($flag) } /** + * Set background color + * * @param int[] $rgbArray * @return $this */ @@ -366,6 +386,8 @@ public function setBackgroundColor(array $rgbArray) } /** + * Set size + * * @param string $size * @return $this */ @@ -420,6 +442,8 @@ public function setBaseFile($file) } /** + * Get base filename + * * @return string */ public function getBaseFile() @@ -428,6 +452,8 @@ public function getBaseFile() } /** + * Get new file + * * @deprecated 101.1.0 * @return bool|string */ @@ -447,6 +473,8 @@ public function isBaseFilePlaceholder() } /** + * Set image processor + * * @param MagentoImage $processor * @return $this */ @@ -457,6 +485,8 @@ public function setImageProcessor($processor) } /** + * Get image processor + * * @return MagentoImage */ public function getImageProcessor() @@ -475,6 +505,8 @@ public function getImageProcessor() } /** + * Resize image + * * @see \Magento\Framework\Image\Adapter\AbstractAdapter * @return $this */ @@ -488,6 +520,8 @@ public function resize() } /** + * Rotate image + * * @param int $angle * @return $this */ @@ -514,6 +548,7 @@ public function setAngle($angle) /** * Add watermark to image + * * size param in format 100x200 * * @param string $file @@ -573,6 +608,8 @@ public function setWatermark( } /** + * Save file + * * @return $this */ public function saveFile() @@ -587,6 +624,8 @@ public function saveFile() } /** + * Get url + * * @return string */ public function getUrl() @@ -595,6 +634,8 @@ public function getUrl() } /** + * Set destination subdir + * * @param string $dir * @return $this */ @@ -605,6 +646,8 @@ public function setDestinationSubdir($dir) } /** + * Get destination subdir + * * @return string */ public function getDestinationSubdir() @@ -613,6 +656,8 @@ public function getDestinationSubdir() } /** + * Check is image cached + * * @return bool */ public function isCached() @@ -780,7 +825,10 @@ public function getWatermarkHeight() } /** + * Clear cache + * * @return void + * @throws \Magento\Framework\Exception\FileSystemException */ public function clearCache() { @@ -793,6 +841,7 @@ public function clearCache() /** * First check this file on FS + * * If it doesn't exist - try to download it from DB * * @param string $filename @@ -811,6 +860,7 @@ protected function _fileExists($filename) /** * Return resized product image information + * * @return array * @throws NotLoadInfoImageException */ diff --git a/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php b/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php index 21fde84931fa6..f6be7f7392b5e 100644 --- a/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php +++ b/app/code/Magento/Catalog/Model/Product/Image/ParamsBuilder.php @@ -65,6 +65,8 @@ public function __construct( } /** + * Build image params + * * @param array $imageArguments * @return array * @SuppressWarnings(PHPMD.NPathComplexity) @@ -85,6 +87,8 @@ public function build(array $imageArguments): array } /** + * Overwrite default values + * * @param array $imageArguments * @return array */ @@ -110,6 +114,8 @@ private function overwriteDefaultValues(array $imageArguments): array } /** + * Get watermark + * * @param string $type * @return array */ @@ -150,6 +156,7 @@ private function getWatermark(string $type): array /** * Get frame from product_image_white_borders + * * @return bool */ private function hasDefaultFrame(): bool From 38abe3d4558df5ffaa91e3ba5ed7fa73c5172a42 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 9 Oct 2018 16:50:25 +0300 Subject: [PATCH 0181/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- app/code/Magento/Catalog/Helper/Image.php | 4 ++-- app/code/Magento/Catalog/Model/Product/Image.php | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Helper/Image.php b/app/code/Magento/Catalog/Helper/Image.php index 4a12bf7093943..170f1209ad9e6 100644 --- a/app/code/Magento/Catalog/Helper/Image.php +++ b/app/code/Magento/Catalog/Helper/Image.php @@ -408,7 +408,7 @@ public function rotate($angle) /** * Add watermark to image * - * size param in format 100x200 + * Size param in format 100x200 * * @param string $fileName * @param string $position @@ -662,7 +662,7 @@ protected function getWatermarkPosition() /** * Set watermark size * - * param size in format 100x200 + * Param size in format 100x200 * * @param string $size * @return $this diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php index 8ad4e89d7b480..adde1263e1bf9 100644 --- a/app/code/Magento/Catalog/Model/Product/Image.php +++ b/app/code/Magento/Catalog/Model/Product/Image.php @@ -549,7 +549,7 @@ public function setAngle($angle) /** * Add watermark to image * - * size param in format 100x200 + * Size param in format 100x200 * * @param string $file * @param string $position @@ -690,7 +690,8 @@ public function getWatermarkFile() /** * Get relative watermark file path - * or false if file not found + * + * Return false if file not found * * @return string | bool */ From dd560f3c985e890fd21cb97b3fd6b5f5b190a312 Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets <yauhen_lyskavets@epam.com> Date: Tue, 9 Oct 2018 16:32:45 +0300 Subject: [PATCH 0182/1158] MAGETWO-91640: Scheduled Import of Products fails on error when errors should be skipped - Integration test fix --- .../integration/testsuite/Magento/Catalog/_files/categories.php | 2 +- .../Magento/CatalogImportExport/Model/Import/ProductTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php index a903274793c34..9a1a6f24dffc8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php @@ -84,7 +84,7 @@ $category = $objectManager->create(\Magento\Catalog\Model\Category::class); $category->isObjectNew(true); $category->setId(6) - ->setName('Category 2') + ->setName('Category 2.1') ->setParentId(2) ->setPath('1/2/6') ->setLevel(2) diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 237d7660da9bd..296c36caed5a0 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -958,6 +958,7 @@ public function testInvalidSkuLink() $errors = $this->_model->setParameters( [ 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, + Import::FIELD_NAME_VALIDATION_STRATEGY => null, 'entity' => 'catalog_product' ] )->setSource( From 6e03f0ff8d21259526d6948de51ed29266241d61 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 9 Oct 2018 17:00:58 +0300 Subject: [PATCH 0183/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../view/adminhtml/templates/browser/content/uploader.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml index c6810f774238c..54f42bb4ecc1f 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml @@ -19,9 +19,9 @@ foreach ($filters as $media_type) { $resizeConfig = ($block->getImageUploadConfigData()->getIsResizeEnabled()) ? "{action: 'resize', maxWidth: " - . $block->escapeHtml($block->getImageUploadMaxWidth()) + . $block->getImageUploadMaxWidth() . ", maxHeight: " - . $block->escapeHtml($block->getImageUploadMaxHeight()) + . $block->getImageUploadMaxHeight() . "}" : "{action: 'resize'}"; ?> @@ -153,7 +153,7 @@ require([ fileTypes: /^image\/(gif|jpeg|png)$/, maxFileSize: <?= (int) $block->getFileSizeService()->getMaxFileSize() ?> * 10 }, - <?= /* @noEscape*/ $resizeConfig ?>, + <?= $block->escapeHtml($resizeConfig) ?>, { action: 'save' }] From 65670eacceaa1d812ff251c2304540859e9b4142 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 9 Oct 2018 18:18:57 +0300 Subject: [PATCH 0184/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Magento/Backend/view/adminhtml/web/js/media-uploader.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js index 2a15f5262bda1..6789dfa3f2b8e 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js @@ -44,7 +44,9 @@ define([ }; if (isResizeEnabled === 0) { - resizeConfiguration = {action: 'resize'}; + resizeConfiguration = { + action: 'resize' + }; } this.element.find('input[type=file]').fileupload({ From 49058889979ca946e886b303541f4fdf116bc958 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Tue, 9 Oct 2018 14:06:13 -0500 Subject: [PATCH 0185/1158] MAGETWO-95505: Broken Swagger markup --- .../Swagger/view/frontend/templates/swagger-ui/index.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml index b20da68734579..4e1b50723782a 100644 --- a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml +++ b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml @@ -17,7 +17,7 @@ * @codingStandardsIgnoreFile */ -$schemaUrl = $block->getSchemaUrl(); +$schemaUrl = $block->escapeUrl($block->getSchemaUrl()); ?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0"> From 1ce85bb8d637310849b2487a035952bf3d23dd20 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Wed, 10 Oct 2018 13:34:29 +0300 Subject: [PATCH 0186/1158] update comments --- .../Ui/DataProvider/NotificationDataProvider.php | 9 ++++++--- app/code/Magento/Sales/Model/Order/Address.php | 6 +++++- .../Magento/Sales/Model/Order/Payment/Transaction.php | 4 +++- app/code/Magento/Store/Model/Store.php | 6 ++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 8418b4f9a753d..737ec1caa7fb1 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -133,7 +133,8 @@ public function setConfigData($config) } /** - * @inheritdoc + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldMetaInfo($fieldSetName, $fieldName) { @@ -141,7 +142,8 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) } /** - * @inheritdoc + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldSetMetaInfo($fieldSetName) { @@ -149,7 +151,8 @@ public function getFieldSetMetaInfo($fieldSetName) } /** - * @inheritdoc + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldsMetaInfo($fieldSetName) { diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index a19c587216b1c..fcaffb0407b4c 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -716,7 +716,11 @@ public function getExtensionAttributes() } /** - * @inheritdoc + * {@inheritdoc} + * + * @param \Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes + * + * @return $this */ public function setExtensionAttributes(\Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 69e79d71db98b..8b8865bab2b71 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -982,7 +982,9 @@ public function setIsClosed($isClosed) } /** - * @inheritdoc + * {@inheritdoc} + * + * @return \Magento\Sales\Api\Data\TransactionExtensionInterface|null */ public function getExtensionAttributes() { diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index ab9b356e7a748..b078942b9e932 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1378,7 +1378,8 @@ public function getStorePath() } /** - * @inheritdoc + * {@inheritdoc} + * @since 100.1.0 */ public function getScopeType() { @@ -1386,7 +1387,8 @@ public function getScopeType() } /** - * @inheritdoc + * {@inheritdoc} + * @since 100.1.0 */ public function getScopeTypeName() { From b0d7a268162d57f3f30a3488fca1afac104ae322 Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets <yauhen_lyskavets@epam.com> Date: Wed, 10 Oct 2018 13:53:30 +0300 Subject: [PATCH 0187/1158] MAGETWO-91679: Bundled SKUs are being assembled based on the product ID number - Integration test fix --- app/code/Magento/Bundle/Model/Product/Type.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index 67441cd944c4f..3729cd945758f 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -310,7 +310,7 @@ public function getSku($product) $selections = $this->getSelectionsByIds($selectionIds, $product); foreach ($selectionIds as $selectionId) { $entity = $selections->getItemByColumnValue('selection_id', $selectionId); - if ($entity->getEntityId()) { + if (isset($entity) && $entity->getEntityId()) { $skuParts[] = $entity->getSku(); } } From 38dadb1f19dfa304083c019ba619ccda4bb44426 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 10 Oct 2018 16:11:33 +0300 Subject: [PATCH 0188/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Magento/Backend/view/adminhtml/web/js/media-uploader.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js index 6789dfa3f2b8e..e1d5a0a9debe5 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js @@ -135,8 +135,7 @@ define([ this.element.find('input[type=file]').fileupload('option', { process: [{ action: 'load', - fileTypes: /^image\/(gif|jpeg|png)$/, - maxFileSize: this.options.maxFileSize + fileTypes: /^image\/(gif|jpeg|png)$/ }, resizeConfiguration, { From 9c19879740e5493eebf6b8e308cc57a26ac07eb1 Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets <yauhen_lyskavets@epam.com> Date: Wed, 10 Oct 2018 17:35:40 +0300 Subject: [PATCH 0189/1158] MAGETWO-91725: Reward Points Balance Update Emails are not being sent when balance change initiated by store front - Bug fix - Integration test fix --- .../Model/Metadata/CustomerMetadata.php | 27 +++++++++---------- app/code/Magento/Customer/etc/di.xml | 7 +++++ .../Customer/Model/CustomerMetadataTest.php | 19 ++++++++----- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php b/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php index 7e8f0b9236fe9..38f3fbcbdbded 100644 --- a/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php +++ b/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php @@ -33,16 +33,26 @@ class CustomerMetadata implements CustomerMetadataInterface */ private $attributeMetadataDataProvider; + /** + * List of system attributes which should be available to the clients. + * + * @var string[] + */ + private $systemAttributes; + /** * @param AttributeMetadataConverter $attributeMetadataConverter * @param AttributeMetadataDataProvider $attributeMetadataDataProvider + * @param string[] $systemAttributes */ public function __construct( AttributeMetadataConverter $attributeMetadataConverter, - AttributeMetadataDataProvider $attributeMetadataDataProvider + AttributeMetadataDataProvider $attributeMetadataDataProvider, + array $systemAttributes = [] ) { $this->attributeMetadataConverter = $attributeMetadataConverter; $this->attributeMetadataDataProvider = $attributeMetadataDataProvider; + $this->systemAttributes = $systemAttributes; } /** @@ -136,7 +146,7 @@ public function getCustomAttributesMetadata($dataObjectClassName = self::DATA_IN if (!$isDataObjectMethod && (!$attributeMetadata->isSystem() - || in_array($attributeCode, $this->getAllowedSystemAttributesList()) + || in_array($attributeCode, $this->systemAttributes) ) ) { $customAttributes[] = $attributeMetadata; @@ -144,17 +154,4 @@ public function getCustomAttributesMetadata($dataObjectClassName = self::DATA_IN } return $customAttributes; } - - /** - * Get list of system attributes which should be available to the clients - * - * @return array - */ - private function getAllowedSystemAttributesList() - { - return [ - 'disable_auto_group_change', - 'reward_update_notification' - ]; - } } diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 6e8c3dc68ed28..209f4794c6fcf 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -127,6 +127,13 @@ <argument name="groupManagement" xsi:type="object">Magento\Customer\Api\GroupManagementInterface\Proxy</argument> </arguments> </type> + <type name="Magento\Customer\Model\Metadata\CustomerMetadata"> + <arguments> + <argument name="systemAttributes" xsi:type="array"> + <item name="disable_auto_group_change" xsi:type="string">disable_auto_group_change</item> + </argument> + </arguments> + </type> <virtualType name="SectionInvalidationConfigReader" type="Magento\Framework\Config\Reader\Filesystem"> <arguments> <argument name="idAttributes" xsi:type="array"> diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php index 336b438661705..794fce17480fa 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php @@ -51,16 +51,23 @@ protected function setUp() public function testGetCustomAttributesMetadata() { - $customAttributesMetadata = $this->service->getCustomAttributesMetadata(); - $this->assertCount(0, $customAttributesMetadata, "Invalid number of attributes returned."); + $customAttributesMetadataQty = count($this->service->getCustomAttributesMetadata()) ; // Verify the consistency of getCustomerAttributeMetadata() function from the 2nd call of the same service - $customAttributesMetadata1 = $this->service->getCustomAttributesMetadata(); - $this->assertCount(0, $customAttributesMetadata1, "Invalid number of attributes returned."); + $customAttributesMetadata1Qty = count($this->service->getCustomAttributesMetadata()); + $this->assertEquals( + $customAttributesMetadataQty, + $customAttributesMetadata1Qty, + "Invalid number of attributes returned." + ); // Verify the consistency of getCustomAttributesMetadata() function from the 2nd service - $customAttributesMetadata2 = $this->serviceTwo->getCustomAttributesMetadata(); - $this->assertCount(0, $customAttributesMetadata2, "Invalid number of attributes returned."); + $customAttributesMetadata2Qty = count($this->serviceTwo->getCustomAttributesMetadata()); + $this->assertEquals( + $customAttributesMetadataQty, + $customAttributesMetadata2Qty, + "Invalid number of attributes returned." + ); } public function testGetNestedOptionsCustomerAttributesMetadata() From d2e66ba244ce394c8eaa2abd2992a9d1d8ded558 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 10 Oct 2018 12:19:58 -0500 Subject: [PATCH 0190/1158] MAGETWO-95588: Swatches on category page does not work - Added configuration for listing pages - Added tests --- .../AdminCreateProductAttributeSection.xml | 1 + .../Mftf/Test/AdminCreateImageSwatchTest.xml | 28 +++++++++++++++++++ .../templates/product/listing/renderer.phtml | 3 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml index 17778c76da9b9..b3ecf5bcedba9 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml @@ -72,5 +72,6 @@ <element name="Scope" type="select" selector="#is_global"/> <element name="AddToColumnOptions" type="select" selector="#is_used_in_grid"/> <element name="UseInFilterOptions" type="select" selector="#is_filterable_in_grid"/> + <element name="UseInProductListing" type="select" selector="#used_in_product_listing"/> </section> </sections> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml index a763bda2e494f..dd497cca2c2de 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml @@ -19,6 +19,7 @@ <group value="Swatches"/> </annotations> <before> + <createData entity="ApiCategory" stepKey="createCategory"/> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> </before> <after> @@ -67,6 +68,11 @@ <click selector="{{AttributePropertiesSection.AdvancedProperties}}" stepKey="expandAdvancedProperties"/> <selectOption selector="{{AttributePropertiesSection.Scope}}" userInput="1" stepKey="selectGlobalScope"/> + <scrollToTopOfPage stepKey="scrollToTabs"/> + <click selector="{{StorefrontPropertiesSection.StoreFrontPropertiesTab}}" stepKey="clickStorefrontPropertiesTab"/> + <waitForElementVisible selector="{{AdvancedAttributePropertiesSection.UseInProductListing}}" stepKey="waitForTabSwitch"/> + <selectOption selector="{{AdvancedAttributePropertiesSection.UseInProductListing}}" userInput="Yes" stepKey="useInProductListing"/> + <!-- Save the new product attribute --> <click selector="{{AttributePropertiesSection.SaveAndEdit}}" stepKey="clickSaveAndEdit1"/> <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" stepKey="waitForSuccess"/> @@ -97,6 +103,7 @@ <actionGroup ref="fillMainProductForm" stepKey="fillProductForm"> <argument name="product" value="BaseConfigurableProduct"/> </actionGroup> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory"/> <!-- Create configurations based off the Image Swatch we created earlier --> <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations"/> @@ -134,5 +141,26 @@ <expectedResult type="string">adobe-base</expectedResult> <actualResult type="string">{$grabSwatch6}</actualResult> </assertContains> + + <!-- Go to the product listing page and see text swatch options --> + <amOnPage url="$$createCategory.name$$.html" stepKey="goToCategoryPageStorefront"/> + <waitForPageLoad stepKey="waitForProductListingPage"/> + + <!-- Verify the storefront --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOption('1')}}" userInput="style" stepKey="grabSwatch7"/> + <assertContains stepKey="assertSwatch7"> + <expectedResult type="string">adobe-thumb</expectedResult> + <actualResult type="string">{$grabSwatch7}</actualResult> + </assertContains> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOption('2')}}" userInput="style" stepKey="grabSwatch8"/> + <assertContains stepKey="assertSwatch8"> + <expectedResult type="string">adobe-small</expectedResult> + <actualResult type="string">{$grabSwatch8}</actualResult> + </assertContains> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOption('3')}}" userInput="style" stepKey="grabSwatch9"/> + <assertContains stepKey="assertSwatch9"> + <expectedResult type="string">adobe-base</expectedResult> + <actualResult type="string">{$grabSwatch9}</actualResult> + </assertContains> </test> </tests> diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml index e65345b38d9b2..410d4046ae17f 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml @@ -21,7 +21,8 @@ $productId = $block->getProduct()->getId(); "numberToShow": <?= /* @escapeNotVerified */ $block->getNumberSwatchesPerProduct(); ?>, "jsonConfig": <?= /* @escapeNotVerified */ $block->getJsonConfig(); ?>, "jsonSwatchConfig": <?= /* @escapeNotVerified */ $block->getJsonSwatchConfig(); ?>, - "mediaCallback": "<?= /* @escapeNotVerified */ $block->getMediaCallback() ?>" + "mediaCallback": "<?= /* @escapeNotVerified */ $block->getMediaCallback() ?>", + "jsonSwatchImageSizeConfig": <?php /* @noEscape */ echo $block->getJsonSwatchSizeConfig() ?> } } } From 43b3cae9c610984b29c976394ca0ab292d61d0a6 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 10 Oct 2018 13:47:31 -0500 Subject: [PATCH 0191/1158] MAGETWO-95588: Swatches on category page does not work - Fixed static issue --- .../view/frontend/templates/product/listing/renderer.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml index 410d4046ae17f..c30c96fc890f7 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml @@ -22,7 +22,7 @@ $productId = $block->getProduct()->getId(); "jsonConfig": <?= /* @escapeNotVerified */ $block->getJsonConfig(); ?>, "jsonSwatchConfig": <?= /* @escapeNotVerified */ $block->getJsonSwatchConfig(); ?>, "mediaCallback": "<?= /* @escapeNotVerified */ $block->getMediaCallback() ?>", - "jsonSwatchImageSizeConfig": <?php /* @noEscape */ echo $block->getJsonSwatchSizeConfig() ?> + "jsonSwatchImageSizeConfig": <?= /* @noEscape */ $block->getJsonSwatchSizeConfig() ?> } } } From 41cb4685fc24b296de837ddf8c39ab377e7347a9 Mon Sep 17 00:00:00 2001 From: Mikalai Shostka <Mikalai_Shostka@epam.com> Date: Thu, 11 Oct 2018 10:24:11 +0300 Subject: [PATCH 0192/1158] MAGETWO-91563: Gift wrapping selection does not display in shopping cart - Add GET interface --- app/code/Magento/Checkout/Controller/Cart/UpdatePost.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php index 9f0dcc6d9c18f..b49635a951e39 100644 --- a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php +++ b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php @@ -8,8 +8,9 @@ use Magento\Checkout\Model\Cart\RequestQuantityProcessor; use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; -class UpdatePost extends \Magento\Checkout\Controller\Cart implements HttpPostActionInterface +class UpdatePost extends \Magento\Checkout\Controller\Cart implements HttpGetActionInterface, HttpPostActionInterface { /** * @var RequestQuantityProcessor From 14b3eaf131298ab8e70bdd529789c91821fbe4a2 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen <michiel@controlaltdelete.nl> Date: Sat, 2 Jun 2018 11:20:25 +0200 Subject: [PATCH 0193/1158] Added checks to see if the payment is available --- .../Observer/SalesOrderBeforeSaveObserver.php | 2 +- .../SalesOrderBeforeSaveObserverTest.php | 28 ++++++++++++++++--- .../Magento/Paypal/Plugin/OrderCanInvoice.php | 4 +++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php index ed8185e6dedeb..465c4916d8abb 100644 --- a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php +++ b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php @@ -21,7 +21,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) /** @var \Magento\Sales\Model\Order $order */ $order = $observer->getEvent()->getOrder(); - if ($order->getPayment()->getMethodInstance()->getCode() != 'free') { + if ($order->getPayment() && $order->getPayment()->getMethodInstance()->getCode() != 'free') { return $this; } diff --git a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php index b86fbc6b18263..47af32d554b68 100644 --- a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php +++ b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php @@ -61,7 +61,7 @@ public function testSalesOrderBeforeSaveCantUnhold() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -86,7 +86,7 @@ public function testSalesOrderBeforeSaveIsCanceled() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -114,7 +114,7 @@ public function testSalesOrderBeforeSaveIsClosed() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -156,6 +156,26 @@ public function testSalesOrderBeforeSaveSetForced() $this->salesOrderBeforeSaveObserver->execute($this->observerMock); } + /** + * The method should check that the payment is available, as this is not always the case. + */ + public function testDoesNothingWhenNoPaymentIsAvailable() + { + $this->_prepareEventMockWithMethods(['getOrder']); + + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class)->disableOriginalConstructor()->setMethods( + array_merge(['__wakeup', 'getPayment']) + )->getMock(); + + $this->eventMock->expects($this->once())->method('getOrder')->will( + $this->returnValue($order) + ); + + $order->expects($this->exactly(1))->method('getPayment')->willReturn(null); + + $this->salesOrderBeforeSaveObserver->execute($this->observerMock); + } + /** * Prepares EventMock with set of methods * @@ -184,7 +204,7 @@ private function _getPreparedOrderMethod($methodCode, $orderMethods = []) $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); diff --git a/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php b/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php index 87abdf8264503..edb50acc5ee76 100644 --- a/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php +++ b/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php @@ -40,6 +40,10 @@ public function __construct(Express $express) */ public function afterCanInvoice(Order $order, bool $result): bool { + if (!$order->getPayment()) { + return false; + } + if ($this->express->isOrderAuthorizationAllowed($order->getPayment())) { return false; } From 3eb6c3e70e65fdadc92f30d4faba77751863580c Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Mon, 8 Oct 2018 10:56:15 +0300 Subject: [PATCH 0194/1158] ENGCOM-2629: Added checks to see if the payment is available #15683 --- .../Payment/Observer/SalesOrderBeforeSaveObserver.php | 9 ++++++++- .../Unit/Observer/SalesOrderBeforeSaveObserverTest.php | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php index 465c4916d8abb..3d520db833164 100644 --- a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php +++ b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php @@ -15,13 +15,20 @@ class SalesOrderBeforeSaveObserver implements ObserverInterface * * @param \Magento\Framework\Event\Observer $observer * @return $this + * @throws \Magento\Framework\Exception\LocalizedException in case order has no payment specified. */ public function execute(\Magento\Framework\Event\Observer $observer) { /** @var \Magento\Sales\Model\Order $order */ $order = $observer->getEvent()->getOrder(); - if ($order->getPayment() && $order->getPayment()->getMethodInstance()->getCode() != 'free') { + if (!$order->getPayment()) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Please provide payment for the order.') + ); + } + + if ($order->getPayment()->getMethodInstance()->getCode() != 'free') { return $this; } diff --git a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php index 47af32d554b68..63ca1b47dc08c 100644 --- a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php +++ b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php @@ -158,6 +158,9 @@ public function testSalesOrderBeforeSaveSetForced() /** * The method should check that the payment is available, as this is not always the case. + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @exceptedExceptionMessage Please provide payment for the order. */ public function testDoesNothingWhenNoPaymentIsAvailable() { From 38b91b77bef7604d747780a3cad2d342d05453d3 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Thu, 11 Oct 2018 11:52:56 +0300 Subject: [PATCH 0195/1158] ENGCOM-1928: 14294 - Fixes 'back' functionality after switching a store view. #15961. Fix functional tests. --- app/code/Magento/Store/Block/Switcher.php | 20 +++++++++++++++++++ .../frontend/templates/switch/languages.phtml | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Store/Block/Switcher.php b/app/code/Magento/Store/Block/Switcher.php index f15349f11066d..e162a2a0abe16 100644 --- a/app/code/Magento/Store/Block/Switcher.php +++ b/app/code/Magento/Store/Block/Switcher.php @@ -265,4 +265,24 @@ public function getTargetStorePostData(Store $store, $data = []) $data ); } + + /** + * Returns target store redirect url. + * + * @param Store $store + * @return string + */ + public function getTargetStoreRedirectUrl(Store $store) + { + return $this->getUrl( + 'stores/store/redirect', + [ + '___store' => $store->getCode(), + '___from_store' => $this->getCurrentStoreCode(), + ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl( + $store->getCurrentUrl(false) + ), + ] + ); + } } diff --git a/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml b/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml index 6d041a9e22c5d..411a1ef3c9a32 100644 --- a/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml +++ b/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml @@ -27,7 +27,7 @@ <?php foreach ($block->getStores() as $_lang): ?> <?php if ($_lang->getId() != $block->getCurrentStoreId()): ?> <li class="view-<?= $block->escapeHtml($_lang->getCode()) ?> switcher-option"> - <a href="<?= $block->escapeUrl($_lang->getCurrentUrl(true)) ?>"> + <a href="<?= $block->escapeUrl($block->getTargetStoreRedirectUrl($_lang)) ?>"> <?= $block->escapeHtml($_lang->getName()) ?> </a> </li> From a0085a80984f0d0c26ef6d1bd93eae6bfa03731c Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Thu, 11 Oct 2018 13:58:35 +0400 Subject: [PATCH 0196/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Add automated test --- ...AdminProductFormGroupedProductsSection.xml | 4 + .../AdminSortingAssociatedProductsTest.xml | 207 ++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminSortingAssociatedProductsTest.xml diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml index 64dcd9566d890..0739c4e601b62 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml @@ -11,5 +11,9 @@ <section name="AdminProductFormGroupedProductsSection"> <element name="toggleGroupedProduct" type="button" selector="div[data-index=grouped] .admin__collapsible-title"/> <element name="addProductsToGroup" type="button" selector="button[data-index='grouped_products_button']" timeout="30"/> + <element name="nextActionButton" type="button" selector="//button[@class='action-next']"/> + <element name="previousActionButton" type="button" selector="//button[@class='action-previous']"/> + <element name="positionProduct" type="input" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[10]//input[@class='position-widget-input']" parameterized="true"/> + <element name="nameProductFromGrid" type="text" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[4]//*[@class='admin__field-control']//span" parameterized="true"/> </section> </sections> \ No newline at end of file diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminSortingAssociatedProductsTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminSortingAssociatedProductsTest.xml new file mode 100644 index 0000000000000..ad5fbbb30edeb --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminSortingAssociatedProductsTest.xml @@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminSortingAssociatedProductsTest"> + <annotations> + <features value="GroupedProduct"/> + <stories value="MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages"/> + <title value="Grouped Products: Sorting Associated Products Between Pages"/> + <description value="Make sure that products in grid were recalculated when sorting associated products between pages"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95085"/> + <group value="GroupedProduct"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="_defaultCategory" stepKey="category"/> + <!-- Create 23 products so that grid can have more than one page --> + <createData entity="ApiSimpleProduct" stepKey="product1"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product2"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product3"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product4"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product5"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product6"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product7"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product8"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product9"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product10"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product11"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product12"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product13"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product14"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product15"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product16"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product17"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product18"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product19"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product20"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product21"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product22"> + <requiredEntity createDataKey="category"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product23"> + <requiredEntity createDataKey="category"/> + </createData> + </before> + <after> + <!--Delete created grouped product--> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" + dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <deleteData createDataKey="product1" stepKey="deleteProduct1"/> + <deleteData createDataKey="product2" stepKey="deleteProduct2"/> + <deleteData createDataKey="product3" stepKey="deleteProduct3"/> + <deleteData createDataKey="product4" stepKey="deleteProduct4"/> + <deleteData createDataKey="product5" stepKey="deleteProduct5"/> + <deleteData createDataKey="product6" stepKey="deleteProduct6"/> + <deleteData createDataKey="product7" stepKey="deleteProduct7"/> + <deleteData createDataKey="product8" stepKey="deleteProduct8"/> + <deleteData createDataKey="product9" stepKey="deleteProduct9"/> + <deleteData createDataKey="product10" stepKey="deleteProduct10"/> + <deleteData createDataKey="product11" stepKey="deleteProduct11"/> + <deleteData createDataKey="product12" stepKey="deleteProduct12"/> + <deleteData createDataKey="product13" stepKey="deleteProduct13"/> + <deleteData createDataKey="product14" stepKey="deleteProduct14"/> + <deleteData createDataKey="product15" stepKey="deleteProduct15"/> + <deleteData createDataKey="product16" stepKey="deleteProduct16"/> + <deleteData createDataKey="product17" stepKey="deleteProduct17"/> + <deleteData createDataKey="product18" stepKey="deleteProduct18"/> + <deleteData createDataKey="product19" stepKey="deleteProduct19"/> + <deleteData createDataKey="product20" stepKey="deleteProduct20"/> + <deleteData createDataKey="product21" stepKey="deleteProduct21"/> + <deleteData createDataKey="product22" stepKey="deleteProduct22"/> + <deleteData createDataKey="product23" stepKey="deleteProduct23"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create grouped Product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPage"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <actionGroup ref="fillGroupedProductForm" stepKey="fillProductForm"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection"/> + <click selector="body" stepKey="clickBodyToCorrectFocusGrouped"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/> + <waitForElementVisible selector="{{AdminAddProductsToGroupPanel.filters}}" stepKey="waitForGroupedProductModal"/> + <actionGroup ref="filterProductGridBySku2" stepKey="filterGroupedProducts"> + <argument name="sku" value="api-simple-product"/> + </actionGroup> + + <!-- Select all, then start the bulk update attributes flow --> + <click selector="{{AdminProductGridSection.multicheckDropdown}}" stepKey="openMulticheckDropdown"/> + <click selector="{{AdminProductGridSection.multicheckOption('Select All')}}" stepKey="selectAllProductInFilteredGrid"/> + + <click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="clickAddSelectedGroupProducts"/> + <waitForPageLoad stepKey="waitForProductsAdded"/> + + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!--Open created Product group--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetFiltersIfExist"/> + <actionGroup ref="searchProductGridByKeyword" stepKey="searchProductGridForm"> + <argument name="keyword" value="GroupedProduct.name"/> + </actionGroup> + <click selector="{{AdminProductGridSection.selectRowBasedOnName(GroupedProduct.name)}}" stepKey="openGroupedProduct"/> + <waitForPageLoad stepKey="waitForProductEditPageLoad"/> + + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection2"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection2"/> + + <!--Change position value for the Product Position 0--> + <grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('1')}}" stepKey="grabNameProductPosition0"/> + <grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('2')}}" stepKey="grabNameProductPositionFirst"/> + <fillField selector="{{AdminProductFormGroupedProductsSection.positionProduct('1')}}" userInput="21" stepKey="fillFieldProductPosition0"/> + <doubleClick selector="{{AdminProductFormGroupedProductsSection.nextActionButton}}" stepKey="clickButton"/> + <waitForAjaxLoad stepKey="waitForAjax1"/> + + <!--Go to next page and verify that Products in grid were recalculated--> + <doubleClick selector="{{AdminProductFormGroupedProductsSection.nextActionButton}}" stepKey="clickNextActionButton"/> + <waitForAjaxLoad stepKey="waitForAjax2"/> + + <grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('2')}}" stepKey="grabNameProductPosition21"/> + <assertEquals stepKey="assertProductsRecalculated"> + <actualResult type="string">$grabNameProductPosition0</actualResult> + <expectedResult type="string">$grabNameProductPosition21</expectedResult> + </assertEquals> + + <!--Change position value for the product to 1--> + <fillField selector="{{AdminProductFormGroupedProductsSection.positionProduct('2')}}" userInput="1" stepKey="fillFieldProductPosition1"/> + <doubleClick selector="{{AdminProductFormGroupedProductsSection.previousActionButton}}" stepKey="clickButton2"/> + <waitForAjaxLoad stepKey="waitForAjax3"/> + + <!--Go to previous page and verify that Products in grid were recalculated--> + <click selector="{{AdminProductFormGroupedProductsSection.previousActionButton}}" stepKey="clickPreviousActionButton"/> + <waitForAjaxLoad stepKey="waitForAjax4"/> + <grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('2')}}" stepKey="grabNameProductPosition2"/> + <grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('1')}}" stepKey="grabNameProductPositionZero"/> + <assertEquals stepKey="assertProductsRecalculated2"> + <actualResult type="string">$grabNameProductPosition2</actualResult> + <expectedResult type="string">$grabNameProductPosition0</expectedResult> + </assertEquals> + <assertEquals stepKey="assertProductsRecalculated3"> + <actualResult type="string">$grabNameProductPositionFirst</actualResult> + <expectedResult type="string">$grabNameProductPositionZero</expectedResult> + </assertEquals> + </test> +</tests> From f03ed7a2e6292f58cc5859422d660e85ec9d5cdb Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Thu, 11 Oct 2018 15:00:48 +0300 Subject: [PATCH 0197/1158] MAGETWO-91563: Gift wrapping selection does not display in shopping cart - Fix static test --- app/code/Magento/Checkout/Controller/Cart/UpdatePost.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php index b49635a951e39..bfc408d920ad3 100644 --- a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php +++ b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,6 +9,9 @@ use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\Action\HttpGetActionInterface; +/** + * Post update shopping cart. + */ class UpdatePost extends \Magento\Checkout\Controller\Cart implements HttpGetActionInterface, HttpPostActionInterface { /** From d3a62b1c8bcdad89d564b0a41f53a08cc81a4fa0 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Thu, 11 Oct 2018 15:32:13 +0300 Subject: [PATCH 0198/1158] MAGETWO-91640: Scheduled Import of Products fails on error when errors should be skipped - Fix integration test --- .../integration/testsuite/Magento/Catalog/_files/categories.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php index 9a1a6f24dffc8..a903274793c34 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php @@ -84,7 +84,7 @@ $category = $objectManager->create(\Magento\Catalog\Model\Category::class); $category->isObjectNew(true); $category->setId(6) - ->setName('Category 2.1') + ->setName('Category 2') ->setParentId(2) ->setPath('1/2/6') ->setLevel(2) From 6e20e2e642bdb8a5fee6b5a0979591ff0b4f71e1 Mon Sep 17 00:00:00 2001 From: vtymchynskyi <vtymchynskyi@magento.com> Date: Thu, 11 Oct 2018 16:39:20 +0300 Subject: [PATCH 0199/1158] MAGETWO-95539: [2.3] Moving Category generate duplicate url_rewrite when 4th level category exist and is translated - Fixed url rewrites regeneration after category moving --- .../Model/Category/Plugin/Category/Move.php | 57 +++++++++++++++++-- .../Model/CategoryUrlRewriteGenerator.php | 8 +++ .../Category/Plugin/Category/MoveTest.php | 33 ++++++++--- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php index 17d12ba563ebd..8a70af213c612 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php @@ -6,9 +6,14 @@ namespace Magento\CatalogUrlRewrite\Model\Category\Plugin\Category; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\CategoryFactory; use Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator; use Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider; +use Magento\Store\Model\Store; +/** + * Perform url updating for children categories. + */ class Move { /** @@ -21,16 +26,24 @@ class Move */ private $childrenCategoriesProvider; + /** + * @var CategoryFactory + */ + private $categoryFactory; + /** * @param CategoryUrlPathGenerator $categoryUrlPathGenerator * @param ChildrenCategoriesProvider $childrenCategoriesProvider + * @param CategoryFactory $categoryFactory */ public function __construct( CategoryUrlPathGenerator $categoryUrlPathGenerator, - ChildrenCategoriesProvider $childrenCategoriesProvider + ChildrenCategoriesProvider $childrenCategoriesProvider, + CategoryFactory $categoryFactory ) { $this->categoryUrlPathGenerator = $categoryUrlPathGenerator; $this->childrenCategoriesProvider = $childrenCategoriesProvider; + $this->categoryFactory = $categoryFactory; } /** @@ -51,20 +64,54 @@ public function afterChangeParent( Category $newParent, $afterCategoryId ) { - $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); - $category->getResource()->saveAttribute($category, 'url_path'); - $this->updateUrlPathForChildren($category); + foreach ($category->getStoreIds() as $storeId) { + $category->setStoreId($storeId); + if (!$this->isGlobalScope($storeId)) { + $this->updateCategoryUrlKeyForStore($category); + $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); + $category->getResource()->saveAttribute($category, 'url_path'); + $this->updateUrlPathForChildren($category); + } + } return $result; } /** + * Set category url_key according to current category store id. + * + * @param Category $category + * @return void + */ + private function updateCategoryUrlKeyForStore(Category $category) + { + $item = $this->categoryFactory->create(); + $item->setStoreId($category->getStoreId()); + $item->load($category->getId()); + $category->setUrlKey($item->getUrlKey()); + } + + /** + * Check is global scope. + * + * @param int|null $storeId + * @return bool + */ + private function isGlobalScope($storeId) + { + return null === $storeId || $storeId == Store::DEFAULT_STORE_ID; + } + + /** + * Updates url_path for child categories. + * * @param Category $category * @return void */ - protected function updateUrlPathForChildren($category) + private function updateUrlPathForChildren($category) { foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) { + $childCategory->setStoreId($category->getStoreId()); $childCategory->unsUrlPath(); $childCategory->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($childCategory)); $childCategory->getResource()->saveAttribute($childCategory, 'url_path'); diff --git a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGenerator.php index b2da0ab39f31f..a86604672e2b4 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGenerator.php @@ -15,6 +15,9 @@ use Magento\Framework\App\ObjectManager; use Magento\UrlRewrite\Model\MergeDataProviderFactory; +/** + * Generate list of urls. + */ class CategoryUrlRewriteGenerator { /** Entity type code */ @@ -84,6 +87,8 @@ public function __construct( } /** + * Generate list of urls. + * * @param \Magento\Catalog\Model\Category $category * @param bool $overrideStoreUrls * @param int|null $rootCategoryId @@ -119,6 +124,7 @@ protected function generateForGlobalScope( $mergeDataProvider = clone $this->mergeDataProviderPrototype; $categoryId = $category->getId(); foreach ($category->getStoreIds() as $storeId) { + $category->setStoreId($storeId); if (!$this->isGlobalScope($storeId) && $this->isOverrideUrlsForStore($storeId, $categoryId, $overrideStoreUrls) ) { @@ -131,6 +137,8 @@ protected function generateForGlobalScope( } /** + * Checks if urls should be overridden for store. + * * @param int $storeId * @param int $categoryId * @param bool $overrideStoreUrls diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php index f91a55c11b974..b69aabe76c35e 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php @@ -5,6 +5,7 @@ */ namespace Magento\CatalogUrlRewrite\Test\Unit\Model\Category\Plugin\Category; +use Magento\Catalog\Model\CategoryFactory; use Magento\CatalogUrlRewrite\Model\Category\Plugin\Category\Move as CategoryMovePlugin; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator; @@ -39,6 +40,11 @@ class MoveTest extends \PHPUnit\Framework\TestCase */ private $categoryMock; + /** + * @var CategoryFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $categoryFactory; + /** * @var CategoryMovePlugin */ @@ -55,28 +61,44 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['getChildren']) ->getMock(); + $this->categoryFactory = $this->getMockBuilder(CategoryFactory::class) + ->disableOriginalConstructor() + ->getMock(); $this->subjectMock = $this->getMockBuilder(CategoryResourceModel::class) ->disableOriginalConstructor() ->getMock(); $this->categoryMock = $this->getMockBuilder(Category::class) ->disableOriginalConstructor() - ->setMethods(['getResource', 'setUrlPath']) + ->setMethods(['getResource', 'setUrlPath', 'getStoreIds']) ->getMock(); $this->plugin = $this->objectManager->getObject( CategoryMovePlugin::class, [ 'categoryUrlPathGenerator' => $this->categoryUrlPathGeneratorMock, - 'childrenCategoriesProvider' => $this->childrenCategoriesProviderMock + 'childrenCategoriesProvider' => $this->childrenCategoriesProviderMock, + 'categoryFactory' => $this->categoryFactory ] ); } + /** + * Tests url updating for children categories. + */ public function testAfterChangeParent() { $urlPath = 'test/path'; - $this->categoryMock->expects($this->once()) - ->method('getResource') + $storeIds = [1]; + $originalCategory = $this->getMockBuilder(Category::class) + ->disableOriginalConstructor() + ->getMock(); + $this->categoryFactory->method('create') + ->willReturn($originalCategory); + + $this->categoryMock->method('getResource') ->willReturn($this->subjectMock); + $this->categoryMock->expects($this->once()) + ->method('getStoreIds') + ->willReturn($storeIds); $this->childrenCategoriesProviderMock->expects($this->once()) ->method('getChildren') ->with($this->categoryMock, true) @@ -85,9 +107,6 @@ public function testAfterChangeParent() ->method('getUrlPath') ->with($this->categoryMock) ->willReturn($urlPath); - $this->categoryMock->expects($this->once()) - ->method('getResource') - ->willReturn($this->subjectMock); $this->categoryMock->expects($this->once()) ->method('setUrlPath') ->with($urlPath); From 66198844e9a8653b3f53b63588d7b071daf65589 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Thu, 11 Oct 2018 17:20:25 +0300 Subject: [PATCH 0200/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Block/DataProviders/ImageUploadConfig.php | 8 ++++---- app/code/Magento/Backend/Block/Media/Uploader.php | 12 ++++++------ ...{ImageUploadConfig.php => UploadResizeConfig.php} | 2 +- ...Interface.php => UploadResizeConfigInterface.php} | 4 ++-- app/code/Magento/Backend/etc/adminhtml/di.xml | 2 +- app/code/Magento/Backend/etc/adminhtml/system.xml | 4 ++-- .../Backend/view/adminhtml/web/js/media-uploader.js | 8 +++----- app/code/Magento/Catalog/etc/adminhtml/system.xml | 2 +- .../Magento/Framework/Image/Adapter/Config.php | 4 ++-- .../Image/Adapter/UploadConfigInterface.php | 4 ++-- 10 files changed, 24 insertions(+), 26 deletions(-) rename app/code/Magento/Backend/Model/Image/{ImageUploadConfig.php => UploadResizeConfig.php} (96%) rename app/code/Magento/Backend/Model/Image/{ImageUploadConfigInterface.php => UploadResizeConfigInterface.php} (89%) diff --git a/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php b/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php index 6ec40cfa0b2d4..9c17b0e5538f4 100644 --- a/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php +++ b/app/code/Magento/Backend/Block/DataProviders/ImageUploadConfig.php @@ -8,7 +8,7 @@ namespace Magento\Backend\Block\DataProviders; use Magento\Framework\View\Element\Block\ArgumentInterface; -use Magento\Backend\Model\Image\ImageUploadConfigInterface; +use Magento\Backend\Model\Image\UploadResizeConfigInterface; /** * Provides additional data for image uploader @@ -16,14 +16,14 @@ class ImageUploadConfig implements ArgumentInterface { /** - * @var ImageUploadConfigInterface + * @var UploadResizeConfigInterface */ private $imageUploadConfig; /** - * @param ImageUploadConfigInterface $imageUploadConfig + * @param UploadResizeConfigInterface $imageUploadConfig */ - public function __construct(ImageUploadConfigInterface $imageUploadConfig) + public function __construct(UploadResizeConfigInterface $imageUploadConfig) { $this->imageUploadConfig = $imageUploadConfig; } diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php index 941d6f37737fe..84fa487281ac8 100644 --- a/app/code/Magento/Backend/Block/Media/Uploader.php +++ b/app/code/Magento/Backend/Block/Media/Uploader.php @@ -10,7 +10,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\Image\Adapter\UploadConfigInterface; -use Magento\Backend\Model\Image\ImageUploadConfigInterface; +use Magento\Backend\Model\Image\UploadResizeConfigInterface; /** * Adminhtml media library uploader @@ -40,14 +40,14 @@ class Uploader extends \Magento\Backend\Block\Widget private $jsonEncoder; /** - * @var ImageUploadConfigInterface + * @var UploadResizeConfigInterface */ private $imageUploadConfig; /** * @var UploadConfigInterface * @deprecated - * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface + * @see \Magento\Backend\Model\Image\UploadResizeConfigInterface */ private $imageConfig; @@ -57,7 +57,7 @@ class Uploader extends \Magento\Backend\Block\Widget * @param array $data * @param Json $jsonEncoder * @param UploadConfigInterface $imageConfig - * @param ImageUploadConfigInterface $imageUploadConfig + * @param UploadResizeConfigInterface $imageUploadConfig */ public function __construct( \Magento\Backend\Block\Template\Context $context, @@ -65,14 +65,14 @@ public function __construct( array $data = [], Json $jsonEncoder = null, UploadConfigInterface $imageConfig = null, - ImageUploadConfigInterface $imageUploadConfig = null + UploadResizeConfigInterface $imageUploadConfig = null ) { $this->_fileSizeService = $fileSize; $this->jsonEncoder = $jsonEncoder ?: ObjectManager::getInstance()->get(Json::class); $this->imageConfig = $imageConfig ?: ObjectManager::getInstance()->get(UploadConfigInterface::class); $this->imageUploadConfig = $imageUploadConfig - ?: ObjectManager::getInstance()->get(ImageUploadConfigInterface::class); + ?: ObjectManager::getInstance()->get(UploadResizeConfigInterface::class); parent::__construct($context, $data); } diff --git a/app/code/Magento/Backend/Model/Image/ImageUploadConfig.php b/app/code/Magento/Backend/Model/Image/UploadResizeConfig.php similarity index 96% rename from app/code/Magento/Backend/Model/Image/ImageUploadConfig.php rename to app/code/Magento/Backend/Model/Image/UploadResizeConfig.php index b7e13b1e8274c..8155aa5e2fe2d 100644 --- a/app/code/Magento/Backend/Model/Image/ImageUploadConfig.php +++ b/app/code/Magento/Backend/Model/Image/UploadResizeConfig.php @@ -10,7 +10,7 @@ /** * Image uploader config provider. */ -class ImageUploadConfig implements ImageUploadConfigInterface +class UploadResizeConfig implements UploadResizeConfigInterface { /** * Config path for the maximal image width value diff --git a/app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php b/app/code/Magento/Backend/Model/Image/UploadResizeConfigInterface.php similarity index 89% rename from app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php rename to app/code/Magento/Backend/Model/Image/UploadResizeConfigInterface.php index 254a13407b2c1..50582dfafbcd1 100644 --- a/app/code/Magento/Backend/Model/Image/ImageUploadConfigInterface.php +++ b/app/code/Magento/Backend/Model/Image/UploadResizeConfigInterface.php @@ -8,11 +8,11 @@ namespace Magento\Backend\Model\Image; /** - * Interface ImageUploadConfigInterface + * Interface UploadResizeConfigInterface * * Used to retrieve configuration for frontend image uploader */ -interface ImageUploadConfigInterface +interface UploadResizeConfigInterface { /** * Get maximal width value for resized image diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml index dcfc99cfed310..4abea272c5495 100644 --- a/app/code/Magento/Backend/etc/adminhtml/di.xml +++ b/app/code/Magento/Backend/etc/adminhtml/di.xml @@ -168,5 +168,5 @@ </arguments> </type> <preference for="CsrfRequestValidator" type="Magento\Backend\App\Request\BackendValidator" /> - <preference for="Magento\Backend\Model\Image\ImageUploadConfigInterface" type="Magento\Backend\Model\Image\ImageUploadConfig" /> + <preference for="Magento\Backend\Model\Image\UploadResizeConfigInterface" type="Magento\Backend\Model\Image\UploadResizeConfig" /> </config> diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml index 3a0d3e50acc5a..2915d8d671a01 100644 --- a/app/code/Magento/Backend/etc/adminhtml/system.xml +++ b/app/code/Magento/Backend/etc/adminhtml/system.xml @@ -339,9 +339,9 @@ <group id="upload_configuration" translate="label" type="text" sortOrder="1000" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Images Upload Configuration</label> <field id="enable_resize" translate="label" type="select" sortOrder="200" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> - <label>Enable Front-end Resize</label> + <label>Enable Frontend Resize</label> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> - <comment>Resize performed by javascript during file upload.</comment> + <comment>Resize performed via javascript before file upload.</comment> </field> <field id="max_width" translate="label comment" type="text" sortOrder="300" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Maximum Width</label> diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js index e1d5a0a9debe5..119e7a35747cb 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js @@ -33,8 +33,7 @@ define([ * @private */ _create: function () { - var - self = this, + var self = this, progressTmpl = mageTemplate('[data-template="uploader"]'), isResizeEnabled = this.options.isResizeEnabled, resizeConfiguration = { @@ -43,7 +42,7 @@ define([ maxHeight: this.options.maxHeight }; - if (isResizeEnabled === 0) { + if (!isResizeEnabled) { resizeConfiguration = { action: 'resize' }; @@ -64,8 +63,7 @@ define([ * @param {Object} data */ add: function (e, data) { - var - fileSize, + var fileSize, tmpl; $.each(data.files, function (index, file) { diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index 2d872fc06b416..74661acb8f136 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -207,7 +207,7 @@ <field id="jpeg_quality" translate="label comment" type="text" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Quality</label> <validate>validate-greater-than-zero validate-number required-entry digits-range-1-100</validate> - <comment>Jpeg quality for images 1-100%.</comment> + <comment>Jpeg quality for resized images 1-100%.</comment> </field> </group> </section> diff --git a/lib/internal/Magento/Framework/Image/Adapter/Config.php b/lib/internal/Magento/Framework/Image/Adapter/Config.php index 84b6b6dcfbdd1..636bbcdcbdb41 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Config.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Config.php @@ -66,7 +66,7 @@ public function getAdapters() * * @return int * @deprecated - * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface::getMaxHeight() + * @see \Magento\Backend\Model\Image\UploadResizeConfigInterface::getMaxHeight() */ public function getMaxWidth(): int { @@ -78,7 +78,7 @@ public function getMaxWidth(): int * * @return int * @deprecated - * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface::getMaxHeight() + * @see \Magento\Backend\Model\Image\UploadResizeConfigInterface::getMaxHeight() */ public function getMaxHeight(): int { diff --git a/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php b/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php index 990062b83ef6f..0a2dbefff8ee0 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php +++ b/lib/internal/Magento/Framework/Image/Adapter/UploadConfigInterface.php @@ -9,8 +9,8 @@ /** * Interface UploadConfigInterface - * @deprecated because new interface was introduced - * @see \Magento\Backend\Model\Image\ImageUploadConfigInterface; + * @deprecated moved to proper namespace and extended + * @see \Magento\Backend\Model\Image\UploadResizeConfigInterface; */ interface UploadConfigInterface { From 09fcc07642fdc8a1b63b00b2150b986a94206d50 Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Wed, 10 Oct 2018 13:51:46 -0500 Subject: [PATCH 0201/1158] MAGETWO-95363: Update Magento\Ui\Controller\Adminhtml\Index\Render\Handle controller --- .../Adminhtml/Index/Render/Handle.php | 30 ++++++++- .../Adminhtml/Index/Render/HandleTest.php | 63 ++++++++++++++++--- .../Adminhtml/Index/Renderer/HandleTest.php | 52 +++++++++++++++ .../Magento/Ui/Model/AuthorizationMock.php | 27 ++++++++ 4 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Ui/Controller/Adminhtml/Index/Renderer/HandleTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Ui/Model/AuthorizationMock.php diff --git a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php index d1254790cb8eb..3b2a81fdac729 100644 --- a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php +++ b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php @@ -23,14 +23,18 @@ class Handle extends AbstractAction implements HttpGetActionInterface */ public function execute() { + $response = ''; $handle = $this->_request->getParam('handle'); $namespace = $this->_request->getParam('namespace'); $buttons = $this->_request->getParam('buttons', false); - $this->_view->loadLayout(['default', $handle], true, true, false); + $component = $this->factory->create($namespace); + if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) { + $this->_view->loadLayout(['default', $handle], true, true, false); - $uiComponent = $this->_view->getLayout()->getBlock($namespace); - $response = $uiComponent instanceof UiComponent ? $uiComponent->toHtml() : ''; + $uiComponent = $this->_view->getLayout()->getBlock($namespace); + $response = $uiComponent instanceof UiComponent ? $uiComponent->toHtml() : ''; + } if ($buttons) { $actionsToolbar = $this->_view->getLayout()->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR); @@ -39,4 +43,24 @@ public function execute() $this->_response->appendBody($response); } + + /** + * Optionally validate ACL resource of components with a DataSource/DataProvider + * + * @param mixed $dataProviderConfigData + * @return bool + */ + private function validateAclResource($dataProviderConfigData) + { + if (isset($dataProviderConfigData['aclResource']) + && !$this->_authorization->isAllowed($dataProviderConfigData['aclResource']) + ) { + if (!$this->_request->isAjax()) { + $this->_redirect('admin/denied'); + } + return false; + } + + return true; + } } diff --git a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php index 31d5b421013f6..e7752678f0c86 100644 --- a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php +++ b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php @@ -6,6 +6,7 @@ namespace Magento\Ui\Test\Unit\Controller\Adminhtml\Index\Render; use Magento\Ui\Controller\Adminhtml\Index\Render\Handle; +use Magento\Framework\View\Element\UiComponent\ContextInterface; class HandleTest extends \PHPUnit\Framework\TestCase { @@ -27,22 +28,42 @@ class HandleTest extends \PHPUnit\Framework\TestCase /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $componentFactoryMock; + protected $viewMock; + + /** + * @var Handle + */ + protected $controller; + + /** + * @var \Magento\Framework\AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $authorizationMock; /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $viewMock; + private $uiComponentContextMock; /** - * @var Handle + * @var \Magento\Framework\View\Element\UiComponentInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $controller; + private $uiComponentMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $uiFactoryMock; + + /** + * @var \Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface| + * \PHPUnit_Framework_MockObject_MockObject + */ + private $dataProviderMock; public function setUp() { $this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $this->componentFactoryMock = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class); $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); $this->contextMock->expects($this->atLeastOnce())->method('getRequest')->willReturn($this->requestMock); @@ -52,8 +73,36 @@ public function setUp() $this->viewMock = $this->createMock(\Magento\Framework\App\ViewInterface::class); $this->contextMock->expects($this->atLeastOnce())->method('getView')->willReturn($this->viewMock); - - $this->controller = new Handle($this->contextMock, $this->componentFactoryMock); + $this->authorizationMock = $this->getMockBuilder(\Magento\Framework\AuthorizationInterface::class) + ->getMockForAbstractClass(); + $this->authorizationMock->expects($this->any()) + ->method('isAllowed') + ->willReturn(true); + $this->uiComponentContextMock = $this->getMockForAbstractClass( + ContextInterface::class + ); + $this->uiComponentMock = $this->getMockForAbstractClass( + \Magento\Framework\View\Element\UiComponentInterface::class + ); + $this->dataProviderMock = $this->getMockForAbstractClass( + \Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface::class + ); + $this->uiComponentContextMock->expects($this->once()) + ->method('getDataProvider') + ->willReturn($this->dataProviderMock); + $this->uiFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponentFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->uiComponentMock->expects($this->any()) + ->method('getContext') + ->willReturn($this->uiComponentContextMock); + $this->uiFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->uiComponentMock); + $this->dataProviderMock->expects($this->once()) + ->method('getConfigData') + ->willReturn([]); + $this->controller = new Handle($this->contextMock, $this->uiFactoryMock); } public function testExecuteNoButtons() diff --git a/dev/tests/integration/testsuite/Magento/Ui/Controller/Adminhtml/Index/Renderer/HandleTest.php b/dev/tests/integration/testsuite/Magento/Ui/Controller/Adminhtml/Index/Renderer/HandleTest.php new file mode 100644 index 0000000000000..dbe721a76e2c6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ui/Controller/Adminhtml/Index/Renderer/HandleTest.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Ui\Controller\Adminhtml\Index\Renderer; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\AuthorizationInterface; + +/** + * @magentoAppArea adminhtml + */ +class HandleTest extends \Magento\TestFramework\TestCase\AbstractBackendController +{ + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testExecuteWhenUserDoesNotHavePermission() + { + Bootstrap::getObjectManager()->configure([ + 'preferences' => [ + AuthorizationInterface::class => \Magento\Ui\Model\AuthorizationMock::class + ] + ]); + $this->getRequest()->setParam('handle', 'customer_index_index'); + $this->getRequest()->setParam('namespace', 'customer_listing'); + $this->getRequest()->setParam('sorting%5Bfield%5D', 'entity_id'); + $this->getRequest()->setParam('paging%5BpageSize%5D', 20); + $this->getRequest()->setParam('isAjax', 1); + $this->dispatch('backend/mui/index/render_handle'); + $output = $this->getResponse()->getBody(); + $this->assertEmpty($output, 'The acl restriction wasn\'t applied properly'); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testExecuteWhenUserHasPermission() + { + $this->getRequest()->setParam('handle', 'customer_index_index'); + $this->getRequest()->setParam('namespace', 'customer_listing'); + $this->getRequest()->setParam('sorting%5Bfield%5D', 'entity_id'); + $this->getRequest()->setParam('paging%5BpageSize%5D', 20); + $this->getRequest()->setParam('isAjax', 1); + $this->dispatch('backend/mui/index/render_handle'); + $output = $this->getResponse()->getBody(); + $this->assertNotEmpty($output, 'The acl restriction wasn\'t applied properly'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Ui/Model/AuthorizationMock.php b/dev/tests/integration/testsuite/Magento/Ui/Model/AuthorizationMock.php new file mode 100644 index 0000000000000..76f472f30eb1f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ui/Model/AuthorizationMock.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Ui\Model; + +/** + * Class AuthorizationMock + */ +class AuthorizationMock extends \Magento\Framework\Authorization +{ + /** + * Check current user permission on resource and privilege + * + * @param string $resource + * @param string $privilege + * @return boolean + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function isAllowed($resource, $privilege = null) + { + return $resource !== 'Magento_Customer::manage'; + } +} From 2eb844f239c68591a6998d279103246609ef4a3d Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Thu, 11 Oct 2018 18:19:10 +0300 Subject: [PATCH 0202/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- app/code/Magento/Catalog/Model/Product/Image.php | 6 +++--- .../view/adminhtml/templates/browser/content/uploader.phtml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php index adde1263e1bf9..a0be36c5a327c 100644 --- a/app/code/Magento/Catalog/Model/Product/Image.php +++ b/app/code/Magento/Catalog/Model/Product/Image.php @@ -45,7 +45,7 @@ class Image extends \Magento\Framework\Model\AbstractModel * Default quality value (for JPEG images only). * * @var int - * @deprecated + * @deprecated use config setting with path self::XML_PATH_JPEG_QUALITY */ protected $_quality = null; @@ -220,7 +220,7 @@ class Image extends \Magento\Framework\Model\AbstractModel * @param SerializerInterface $serializer * @param ParamsBuilder $paramsBuilder * @SuppressWarnings(PHPMD.ExcessiveParameterList) - * @SuppressWarnings(PHPMD.UnusedLocalVariable)1 + * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ public function __construct( \Magento\Framework\Model\Context $context, @@ -305,7 +305,7 @@ public function getHeight() * * @param int $quality * @return $this - * @deprecated + * @deprecated use config setting with path self::XML_PATH_JPEG_QUALITY */ public function setQuality($quality) { diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml index 54f42bb4ecc1f..df0a74c48ac23 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml @@ -17,7 +17,7 @@ foreach ($filters as $media_type) { }, $media_type['files'])); } -$resizeConfig = ($block->getImageUploadConfigData()->getIsResizeEnabled()) +$resizeConfig = $block->getImageUploadConfigData()->getIsResizeEnabled() ? "{action: 'resize', maxWidth: " . $block->getImageUploadMaxWidth() . ", maxHeight: " From 0ec20f5a77fd11fc61d6a0d297bbd6ab09296a78 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 11 Oct 2018 11:16:23 -0500 Subject: [PATCH 0203/1158] MAGETWO-95588: Swatches on category page does not work - CR feedback --- .../Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml index dd497cca2c2de..0e294153e881e 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateImageSwatchTest.xml @@ -23,7 +23,8 @@ <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> </before> <after> - <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> </after> <!-- Begin creating a new product attribute of type "Image Swatch" --> From c19c00b1385176502ff4961503f6d8fb480f6907 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Thu, 11 Oct 2018 15:17:28 -0500 Subject: [PATCH 0204/1158] MAGETWO-95234: Change regular expression --- app/code/Magento/Sales/Helper/Admin.php | 19 ++++++++-- lib/internal/Magento/Framework/Escaper.php | 42 ++++++++++++++++++---- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Sales/Helper/Admin.php b/app/code/Magento/Sales/Helper/Admin.php index 45a6dd1252ba3..6b38f0046a983 100644 --- a/app/code/Magento/Sales/Helper/Admin.php +++ b/app/code/Magento/Sales/Helper/Admin.php @@ -3,8 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Helper; +/** + * Sales admin helper. + */ class Admin extends \Magento\Framework\App\Helper\AbstractHelper { /** @@ -148,11 +153,19 @@ public function escapeHtmlWithLinks($data, $allowedTags = null) $links = []; $i = 1; $data = str_replace('%', '%%', $data); - $regexp = "/<a\s[^>]*href\s*?=\s*?([\"\']??)([^\" >]*?)\\1[^>]*>(.*)<\/a>/siU"; + $regexp = "#(?J)<a" + ."(?:(?:\s+(?:(?:href\s*=\s*(['\"])(?<link>.*?)\\1\s*)|(?:\S+\s*=\s*(['\"])(.*?)\\3)\s*)*)|>)" + .">?(?:(?:(?<text>.*?)(?:<\/a\s*>?|(?=<\w))|(?<text>.*)))#si"; while (preg_match($regexp, $data, $matches)) { + $text = ''; + $url = ''; //Revert the sprintf escaping - $url = str_replace('%%', '%', $matches[2]); - $text = str_replace('%%', '%', $matches[3]); + if (!empty($matches['link'])) { + $url = str_replace('%%', '%', $matches['link']); + } + if (!empty($matches['text'])) { + $text = str_replace('%%', '%', $matches['text']); + } //Check for an valid url if ($url) { $urlScheme = strtolower(parse_url($url, PHP_URL_SCHEME)); diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php index fec64378189eb..d0181c2651868 100644 --- a/lib/internal/Magento/Framework/Escaper.php +++ b/lib/internal/Magento/Framework/Escaper.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework; /** @@ -32,13 +33,23 @@ class Escaper */ private $allowedAttributes = ['id', 'class', 'href', 'target', 'title', 'style']; + /** + * @var string + */ + private static $xssFiltrationPattern = + '/((javascript(\\\\x3a|:|%3A))|(data(\\\\x3a|:|%3A))|(vbscript:))|' + . '((\\\\x6A\\\\x61\\\\x76\\\\x61\\\\x73\\\\x63\\\\x72\\\\x69\\\\x70\\\\x74(\\\\x3a|:|%3A))|' + . '(\\\\x64\\\\x61\\\\x74\\\\x61(\\\\x3a|:|%3A)))/i'; + /** * @var string[] */ private $escapeAsUrlAttributes = ['href']; /** - * Escape string for HTML context. allowedTags will not be escaped, except the following: script, img, embed, + * Escape string for HTML context. + * + * AllowedTags will not be escaped, except the following: script, img, embed, * iframe, video, source, object, audio * * @param string|array $data @@ -285,7 +296,6 @@ public function escapeJsQuote($data, $quote = '\'') /** * Escape xss in urls - * Remove `javascript:`, `vbscript:`, `data:` words from url * * @param string $data * @return string @@ -293,15 +303,33 @@ public function escapeJsQuote($data, $quote = '\'') */ public function escapeXssInUrl($data) { - $pattern = '/((javascript(\\\\x3a|:|%3A))|(data(\\\\x3a|:|%3A))|(vbscript:))|' - . '((\\\\x6A\\\\x61\\\\x76\\\\x61\\\\x73\\\\x63\\\\x72\\\\x69\\\\x70\\\\x74(\\\\x3a|:|%3A))|' - . '(\\\\x64\\\\x61\\\\x74\\\\x61(\\\\x3a|:|%3A)))/i'; - $result = preg_replace($pattern, ':', $data); - return htmlspecialchars($result, ENT_COMPAT | ENT_HTML5 | ENT_HTML401, 'UTF-8', false); + return htmlspecialchars( + $this->escapeScriptIdentifiers($data), + ENT_COMPAT | ENT_HTML5 | ENT_HTML401, + 'UTF-8', + false + ); + } + + /** + * Remove `javascript:`, `vbscript:`, `data:` words from the string. + * + * @param string $data + * @return string + */ + private function escapeScriptIdentifiers(string $data): string + { + $filteredData = preg_replace(self::$xssFiltrationPattern, ':', $data) ?: ''; + if (preg_match(self::$xssFiltrationPattern, $filteredData)) { + $filteredData = $this->escapeScriptIdentifiers($filteredData); + } + + return $filteredData; } /** * Escape quotes inside html attributes + * * Use $addSlashes = false for escaping js that inside html attribute (onClick, onSubmit etc) * * @param string $data From 93b8f297f0890a88deb52e8baefb09af1bed8abf Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Fri, 12 Oct 2018 14:03:11 +0300 Subject: [PATCH 0205/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fix static tests --- .../Block/Product/ProductList/Toolbar.php | 14 ++++++++++++++ .../view/frontend/web/js/product/list/toolbar.js | 16 ++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 12c691d1365c3..c7a9fcce7bf7a 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -430,6 +430,8 @@ public function getPagerUrl($params = []) } /** + * Get pager encoded url. + * * @param array $params * @return string */ @@ -624,6 +626,8 @@ public function getLimit() } /** + * Check if limit is current used in toolbar. + * * @param int $limit * @return bool */ @@ -633,6 +637,8 @@ public function isLimitCurrent($limit) } /** + * Pager number of items from which products started on current page. + * * @return int */ public function getFirstNum() @@ -642,6 +648,8 @@ public function getFirstNum() } /** + * Pager number of items products finished on current page. + * * @return int */ public function getLastNum() @@ -651,6 +659,8 @@ public function getLastNum() } /** + * Total number of products in current category. + * * @return int */ public function getTotalNum() @@ -659,6 +669,8 @@ public function getTotalNum() } /** + * Check if current page is the first. + * * @return bool */ public function isFirstPage() @@ -667,6 +679,8 @@ public function isFirstPage() } /** + * Return last page number. + * * @return int */ public function getLastPageNum() diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js b/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js index 7c47f5bd04d5a..b8b6ff65be2b4 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js @@ -91,7 +91,7 @@ define([ baseUrl = urlPaths[0], urlParams = urlPaths[1] ? urlPaths[1].split('&') : [], paramData = {}, - parameters, i; + parameters, i, form, params, key, input, formKey; for (i = 0; i < urlParams.length; i++) { parameters = urlParams[i].split('='); @@ -102,25 +102,25 @@ define([ paramData[paramName] = paramValue; if (this.options.post) { - var form = document.createElement('form'); + form = document.createElement('form'); + params = [this.options.mode, this.options.direction, this.options.order, this.options.limit]; - var params = [this.options.mode, this.options.direction, this.options.order, this.options.limit]; - for (var key in paramData) { - if (params.indexOf(key) !== -1) { - var input = document.createElement('input'); + for (key in paramData) { + if (params.indexOf(key) !== -1) { //eslint-disable-line max-depth + input = document.createElement('input'); input.name = key; input.value = paramData[key]; form.appendChild(input); delete paramData[key]; } } - var formKey = document.createElement('input'); + formKey = document.createElement('input'); formKey.name = 'form_key'; formKey.value = this.options.formKey; form.appendChild(formKey); paramData = $.param(paramData); - baseUrl = baseUrl + (paramData.length ? '?' + paramData : ''); + baseUrl += paramData.length ? '?' + paramData : ''; form.action = baseUrl; form.method = 'POST'; From 9c01411858079ff9c12b968ea8d681f6edad39b7 Mon Sep 17 00:00:00 2001 From: Vinai Kopp <vinai@netzarbeiter.com> Date: Thu, 14 Jun 2018 09:48:26 +0200 Subject: [PATCH 0206/1158] Fix typehint of customer-data updateSectionId parameters The typehint wrongly indicates the parameter should be a number, where in fact it is a boolean. It is passed through to the server side to the controller action \Magento\Customer\Controller\Section\Load::execute() where it is cast to a boolean and passed as the $updateIds parameter to \Magento\Customer\CustomerData\SectionPool::getSectionsData() and from there as the boolean parameter $forceUpdate to the \Magento\Customer\CustomerData\Section\Identifier::initMark() method. This PR introduces no backward incompatibilities, it only fixes the type hint to make the code more readable and improve compatibility with static code analysis tools. --- .../Magento/Customer/view/frontend/web/js/customer-data.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index cfa06c6e12003..8cbc779a99ab0 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -75,7 +75,7 @@ define([ /** * @param {Object} sectionNames - * @param {Number} updateSectionId + * @param {Boolean} updateSectionId * @return {*} */ getFromServer: function (sectionNames, updateSectionId) { @@ -326,7 +326,7 @@ define([ /** * @param {Array} sectionNames - * @param {Number} updateSectionId + * @param {Boolean} updateSectionId * @return {*} */ reload: function (sectionNames, updateSectionId) { From 696a0c22dac2b426c0685d9b626c323fd62709b1 Mon Sep 17 00:00:00 2001 From: Vinai Kopp <vinai@netzarbeiter.com> Date: Sat, 16 Jun 2018 20:51:24 +0200 Subject: [PATCH 0207/1158] Rename parameter variable to make intent more easy to understand. --- .../Customer/view/frontend/web/js/customer-data.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index 8cbc779a99ab0..07d08847aa4ea 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -75,17 +75,17 @@ define([ /** * @param {Object} sectionNames - * @param {Boolean} updateSectionId + * @param {Boolean} forceNewSectionTimestamp * @return {*} */ - getFromServer: function (sectionNames, updateSectionId) { + getFromServer: function (sectionNames, forceNewSectionTimestamp) { var parameters; sectionNames = sectionConfig.filterClientSideSections(sectionNames); parameters = _.isArray(sectionNames) ? { sections: sectionNames.join(',') } : []; - parameters['update_section_id'] = updateSectionId; + parameters['update_section_id'] = forceNewSectionTimestamp; return $.getJSON(options.sectionLoadUrl, parameters).fail(function (jqXHR) { throw new Error(jqXHR); @@ -326,11 +326,11 @@ define([ /** * @param {Array} sectionNames - * @param {Boolean} updateSectionId + * @param {Boolean} forceNewSectionTimestamp * @return {*} */ - reload: function (sectionNames, updateSectionId) { - return dataProvider.getFromServer(sectionNames, updateSectionId).done(function (sections) { + reload: function (sectionNames, forceNewSectionTimestamp) { + return dataProvider.getFromServer(sectionNames, forceNewSectionTimestamp).done(function (sections) { $(document).trigger('customer-data-reload', [sectionNames]); buffer.update(sections); }); From 3621c3c9b72278c8fd0b95c88eb9b9475dd4b51e Mon Sep 17 00:00:00 2001 From: Vinai Kopp <vinai@netzarbeiter.com> Date: Fri, 22 Jun 2018 08:47:36 -0400 Subject: [PATCH 0208/1158] Rename request parameter and variables to make them more expressive --- .../Customer/Controller/Section/Load.php | 8 +++---- .../CustomerData/Section/Identifier.php | 14 +++++------ .../Customer/CustomerData/SectionPool.php | 4 ++-- .../CustomerData/SectionPoolInterface.php | 4 ++-- .../Test/Unit/Controller/Section/LoadTest.php | 24 +++++++++---------- .../Unit/CustomerData/SectionPoolTest.php | 2 +- .../view/frontend/web/js/customer-data.js | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Section/Load.php b/app/code/Magento/Customer/Controller/Section/Load.php index e55b1d0df26c7..89d4417c79c19 100644 --- a/app/code/Magento/Customer/Controller/Section/Load.php +++ b/app/code/Magento/Customer/Controller/Section/Load.php @@ -71,11 +71,11 @@ public function execute() $sectionNames = $this->getRequest()->getParam('sections'); $sectionNames = $sectionNames ? array_unique(\explode(',', $sectionNames)) : null; - $updateSectionId = $this->getRequest()->getParam('update_section_id'); - if ('false' === $updateSectionId) { - $updateSectionId = false; + $forceNewSectionTimestamp = $this->getRequest()->getParam('force_new_section_timestamp'); + if ('false' === $forceNewSectionTimestamp) { + $forceNewSectionTimestamp = false; } - $response = $this->sectionPool->getSectionsData($sectionNames, (bool)$updateSectionId); + $response = $this->sectionPool->getSectionsData($sectionNames, (bool)$forceNewSectionTimestamp); } catch (\Exception $e) { $resultJson->setStatusHeader( \Zend\Http\Response::STATUS_CODE_400, diff --git a/app/code/Magento/Customer/CustomerData/Section/Identifier.php b/app/code/Magento/Customer/CustomerData/Section/Identifier.php index 2a770925d1c37..54d7cee2d90bd 100644 --- a/app/code/Magento/Customer/CustomerData/Section/Identifier.php +++ b/app/code/Magento/Customer/CustomerData/Section/Identifier.php @@ -43,12 +43,12 @@ public function __construct( /** * Init mark(identifier) for sections * - * @param bool $forceUpdate + * @param bool $forceNewTimestamp * @return int */ - public function initMark($forceUpdate) + public function initMark($forceNewTimestamp) { - if ($forceUpdate) { + if ($forceNewTimestamp) { $this->markId = time(); return $this->markId; } @@ -68,18 +68,18 @@ public function initMark($forceUpdate) * * @param array $sectionsData * @param null $sectionNames - * @param bool $updateIds + * @param bool $forceNewTimestamp * @return array */ - public function markSections(array $sectionsData, $sectionNames = null, $updateIds = false) + public function markSections(array $sectionsData, $sectionNames = null, $forceNewTimestamp = false) { if (!$sectionNames) { $sectionNames = array_keys($sectionsData); } - $markId = $this->initMark($updateIds); + $markId = $this->initMark($forceNewTimestamp); foreach ($sectionNames as $name) { - if ($updateIds || !array_key_exists(self::SECTION_KEY, $sectionsData[$name])) { + if ($forceNewTimestamp || !array_key_exists(self::SECTION_KEY, $sectionsData[$name])) { $sectionsData[$name][self::SECTION_KEY] = $markId; } } diff --git a/app/code/Magento/Customer/CustomerData/SectionPool.php b/app/code/Magento/Customer/CustomerData/SectionPool.php index 0e0d7b992e33a..618d52079973d 100644 --- a/app/code/Magento/Customer/CustomerData/SectionPool.php +++ b/app/code/Magento/Customer/CustomerData/SectionPool.php @@ -55,10 +55,10 @@ public function __construct( /** * {@inheritdoc} */ - public function getSectionsData(array $sectionNames = null, $updateIds = false) + public function getSectionsData(array $sectionNames = null, $forceNewTimestamp = false) { $sectionsData = $sectionNames ? $this->getSectionDataByNames($sectionNames) : $this->getAllSectionData(); - $sectionsData = $this->identifier->markSections($sectionsData, $sectionNames, $updateIds); + $sectionsData = $this->identifier->markSections($sectionsData, $sectionNames, $forceNewTimestamp); return $sectionsData; } diff --git a/app/code/Magento/Customer/CustomerData/SectionPoolInterface.php b/app/code/Magento/Customer/CustomerData/SectionPoolInterface.php index c308804fd0f8d..ad73b9722b133 100644 --- a/app/code/Magento/Customer/CustomerData/SectionPoolInterface.php +++ b/app/code/Magento/Customer/CustomerData/SectionPoolInterface.php @@ -14,8 +14,8 @@ interface SectionPoolInterface * Get section data by section names. If $sectionNames is null then return all sections data * * @param array $sectionNames - * @param bool $updateIds + * @param bool $forceNewTimestamp * @return array */ - public function getSectionsData(array $sectionNames = null, $updateIds = false); + public function getSectionsData(array $sectionNames = null, $forceNewTimestamp = false); } diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Section/LoadTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Section/LoadTest.php index f4bf184f9ebf2..5a7cf42be2c7e 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Section/LoadTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Section/LoadTest.php @@ -83,13 +83,13 @@ protected function setUp() } /** - * @param $sectionNames - * @param $updateSectionID - * @param $sectionNamesAsArray - * @param $updateIds + * @param string $sectionNames + * @param bool $forceNewSectionTimestamp + * @param string[] $sectionNamesAsArray + * @param bool $forceNewTimestamp * @dataProvider executeDataProvider */ - public function testExecute($sectionNames, $updateSectionID, $sectionNamesAsArray, $updateIds) + public function testExecute($sectionNames, $forceNewSectionTimestamp, $sectionNamesAsArray, $forceNewTimestamp) { $this->resultJsonFactoryMock->expects($this->once()) ->method('create') @@ -103,12 +103,12 @@ public function testExecute($sectionNames, $updateSectionID, $sectionNamesAsArra $this->httpRequestMock->expects($this->exactly(2)) ->method('getParam') - ->withConsecutive(['sections'], ['update_section_id']) - ->willReturnOnConsecutiveCalls($sectionNames, $updateSectionID); + ->withConsecutive(['sections'], ['force_new_section_timestamp']) + ->willReturnOnConsecutiveCalls($sectionNames, $forceNewSectionTimestamp); $this->sectionPoolMock->expects($this->once()) ->method('getSectionsData') - ->with($sectionNamesAsArray, $updateIds) + ->with($sectionNamesAsArray, $forceNewTimestamp) ->willReturn([ 'message' => 'some message', 'someKey' => 'someValue' @@ -133,15 +133,15 @@ public function executeDataProvider() return [ [ 'sectionNames' => 'sectionName1,sectionName2,sectionName3', - 'updateSectionID' => 'updateSectionID', + 'forceNewSectionTimestamp' => 'forceNewSectionTimestamp', 'sectionNamesAsArray' => ['sectionName1', 'sectionName2', 'sectionName3'], - 'updateIds' => true + 'forceNewTimestamp' => true ], [ 'sectionNames' => null, - 'updateSectionID' => null, + 'forceNewSectionTimestamp' => null, 'sectionNamesAsArray' => null, - 'updateIds' => false + 'forceNewTimestamp' => false ], ]; } diff --git a/app/code/Magento/Customer/Test/Unit/CustomerData/SectionPoolTest.php b/app/code/Magento/Customer/Test/Unit/CustomerData/SectionPoolTest.php index 98fee70e335f7..2b67df1aee292 100644 --- a/app/code/Magento/Customer/Test/Unit/CustomerData/SectionPoolTest.php +++ b/app/code/Magento/Customer/Test/Unit/CustomerData/SectionPoolTest.php @@ -63,7 +63,7 @@ public function testGetSectionsDataAllSections() $this->identifierMock->expects($this->once()) ->method('markSections') - //check also default value for $updateIds = false + //check also default value for $forceTimestamp = false ->with($allSectionsData, $sectionNames, false) ->willReturn($identifierResult); $modelResult = $this->model->getSectionsData($sectionNames); diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index 07d08847aa4ea..39e3f8d95ee3b 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -85,7 +85,7 @@ define([ parameters = _.isArray(sectionNames) ? { sections: sectionNames.join(',') } : []; - parameters['update_section_id'] = forceNewSectionTimestamp; + parameters['force_new_section_timestamp'] = forceNewSectionTimestamp; return $.getJSON(options.sectionLoadUrl, parameters).fail(function (jqXHR) { throw new Error(jqXHR); From c404de46a22640bfe844d9bbc63c28fe0ea0bffc Mon Sep 17 00:00:00 2001 From: Vinai Kopp <vinai@netzarbeiter.com> Date: Sat, 23 Jun 2018 17:40:12 +0200 Subject: [PATCH 0209/1158] Update query parameter name in performance toolkit to match new name in code --- setup/performance-toolkit/benchmark.jmx | 76 ++++++++++---------- setup/performance-toolkit/benchmark_2015.jmx | 36 +++++----- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 8b295c9f5fc46..e8e033fe59024 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -2881,12 +2881,12 @@ vars.put("customer_email", customerUser); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -4906,12 +4906,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -5272,12 +5272,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -5566,12 +5566,12 @@ vars.put("customer_email", customerUser); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -5739,12 +5739,12 @@ vars.put("product_sku", product.get("sku")); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -6171,12 +6171,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -6349,12 +6349,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -6787,12 +6787,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -7153,12 +7153,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -7869,12 +7869,12 @@ vars.put("customer_email", customerUser); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -8105,12 +8105,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -8471,12 +8471,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -9146,12 +9146,12 @@ vars.put("customer_email", customerUser); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -9330,12 +9330,12 @@ vars.put("product_sku", product.get("sku")); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -9662,12 +9662,12 @@ vars.put("customer_email", customerUser); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -9929,12 +9929,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -10295,12 +10295,12 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -10492,12 +10492,12 @@ vars.put("item_id", vars.get("cart_items_qty_inputs_" + id)); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> @@ -10813,12 +10813,12 @@ vars.put("customer_email", customerUser); <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">false</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index 8be7749a08bc4..e58e610304199 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -2981,12 +2981,12 @@ vars.put("loadType", "Guest");</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> @@ -3217,12 +3217,12 @@ vars.put("loadType", "Guest");</stringProp> <stringProp name="Argument.name">sections</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> @@ -3565,12 +3565,12 @@ vars.put("loadType", "Guest");</stringProp> <stringProp name="Argument.name">sections</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> @@ -4039,12 +4039,12 @@ vars.put("loadType", "Guest");</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> @@ -4275,12 +4275,12 @@ vars.put("loadType", "Guest");</stringProp> <stringProp name="Argument.name">sections</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> @@ -4623,12 +4623,12 @@ vars.put("loadType", "Guest");</stringProp> <stringProp name="Argument.name">sections</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> @@ -5637,12 +5637,12 @@ vars.put("loadType", "Customer");</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> @@ -5873,12 +5873,12 @@ vars.put("loadType", "Customer");</stringProp> <stringProp name="Argument.name">sections</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> @@ -6221,12 +6221,12 @@ vars.put("loadType", "Customer");</stringProp> <stringProp name="Argument.name">sections</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> - <elementProp name="update_section_id" elementType="HTTPArgument"> + <elementProp name="force_new_section_timestamp" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">true</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">update_section_id</stringProp> + <stringProp name="Argument.name">force_new_section_timestamp</stringProp> <stringProp name="Argument.desc">true</stringProp> </elementProp> <elementProp name="_" elementType="HTTPArgument"> From e86018e14e4ecf79b5df06352c952580e54aa6bf Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Fri, 12 Oct 2018 10:10:11 -0500 Subject: [PATCH 0210/1158] MAGETWO-95234: Change regular expression --- app/code/Magento/Sales/Helper/Admin.php | 40 +++++++++++-------- lib/internal/Magento/Framework/Escaper.php | 10 +++-- .../Framework/View/Element/AbstractBlock.php | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Sales/Helper/Admin.php b/app/code/Magento/Sales/Helper/Admin.php index 6b38f0046a983..22d3b76b6c920 100644 --- a/app/code/Magento/Sales/Helper/Admin.php +++ b/app/code/Magento/Sales/Helper/Admin.php @@ -158,25 +158,10 @@ public function escapeHtmlWithLinks($data, $allowedTags = null) .">?(?:(?:(?<text>.*?)(?:<\/a\s*>?|(?=<\w))|(?<text>.*)))#si"; while (preg_match($regexp, $data, $matches)) { $text = ''; - $url = ''; - //Revert the sprintf escaping - if (!empty($matches['link'])) { - $url = str_replace('%%', '%', $matches['link']); - } if (!empty($matches['text'])) { $text = str_replace('%%', '%', $matches['text']); } - //Check for an valid url - if ($url) { - $urlScheme = strtolower(parse_url($url, PHP_URL_SCHEME)); - if ($urlScheme !== 'http' && $urlScheme !== 'https') { - $url = null; - } - } - //Use hash tag as fallback - if (!$url) { - $url = '#'; - } + $url = $this->filterUrl($matches['link'] ?? ''); //Recreate a minimalistic secure a tag $links[] = sprintf( '<a href="%s">%s</a>', @@ -191,4 +176,27 @@ public function escapeHtmlWithLinks($data, $allowedTags = null) } return $this->escaper->escapeHtml($data, $allowedTags); } + + /** + * Filter the URL for allowed protocols. + * + * @param string $url + * @return string + */ + private function filterUrl(string $url): string + { + if ($url) { + //Revert the sprintf escaping + $url = str_replace('%%', '%', $url); + $urlScheme = parse_url($url, PHP_URL_SCHEME); + $urlScheme = $urlScheme ? strtolower($urlScheme) : ''; + if ($urlScheme !== 'http' && $urlScheme !== 'https') { + $url = null; + } + } else { + $url = '#'; + } + + return $url; + } } diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php index d0181c2651868..4546de7978e5b 100644 --- a/lib/internal/Magento/Framework/Escaper.php +++ b/lib/internal/Magento/Framework/Escaper.php @@ -58,6 +58,10 @@ class Escaper */ public function escapeHtml($data, $allowedTags = null) { + if (!is_array($data)) { + $data = (string)$data; + } + if (is_array($data)) { $result = []; foreach ($data as $item) { @@ -208,7 +212,7 @@ public function escapeHtmlAttr($string, $escapeSingleQuote = true) if ($escapeSingleQuote) { return $this->getEscaper()->escapeHtmlAttr((string) $string); } - return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false); + return htmlspecialchars((string)$string, ENT_COMPAT, 'UTF-8', false); } /** @@ -289,7 +293,7 @@ public function escapeJsQuote($data, $quote = '\'') $result[] = $this->escapeJsQuote($item, $quote); } } else { - $result = str_replace($quote, '\\' . $quote, $data); + $result = str_replace($quote, '\\' . $quote, (string)$data); } return $result; } @@ -304,7 +308,7 @@ public function escapeJsQuote($data, $quote = '\'') public function escapeXssInUrl($data) { return htmlspecialchars( - $this->escapeScriptIdentifiers($data), + $this->escapeScriptIdentifiers((string)$data), ENT_COMPAT | ENT_HTML5 | ENT_HTML401, 'UTF-8', false diff --git a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php index b2f857bf29f45..3f88504f051e0 100644 --- a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php +++ b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php @@ -952,7 +952,7 @@ public function stripTags($data, $allowableTags = null, $allowHtmlEntities = fal */ public function escapeUrl($string) { - return $this->_escaper->escapeUrl($string); + return $this->_escaper->escapeUrl((string)$string); } /** From da2b587418fb53f68795c13ba667cbbf86425870 Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Wed, 10 Oct 2018 16:57:31 -0500 Subject: [PATCH 0211/1158] MAGETWO-95633: Updating default value for protected_extensions setting --- app/code/Magento/Store/etc/config.xml | 2 ++ .../Validator/NotProtectedExtensionTest.php | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Code/File/Validator/NotProtectedExtensionTest.php diff --git a/app/code/Magento/Store/etc/config.xml b/app/code/Magento/Store/etc/config.xml index d69fcad7aac61..b9e7ac1c6aca0 100644 --- a/app/code/Magento/Store/etc/config.xml +++ b/app/code/Magento/Store/etc/config.xml @@ -130,6 +130,8 @@ <html>html</html> <phtml>phtml</phtml> <shtml>shtml</shtml> + <phpt>phpt</phpt> + <pht>pht</pht> </protected_extensions> <public_files_valid_paths> <protected> diff --git a/dev/tests/integration/testsuite/Magento/Framework/Code/File/Validator/NotProtectedExtensionTest.php b/dev/tests/integration/testsuite/Magento/Framework/Code/File/Validator/NotProtectedExtensionTest.php new file mode 100644 index 0000000000000..622f17cbf9ce7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Code/File/Validator/NotProtectedExtensionTest.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Code\File\Validator; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Class NotProtectedExtension + */ +class NotProtectedExtensionTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test that phpt, pht is invalid extension type + * @dataProvider isValidDataProvider + */ + public function testIsValid($extension) + { + $objectManager = Bootstrap::getObjectManager(); + /** @var \Magento\MediaStorage\Model\File\Validator\NotProtectedExtension $model */ + $model = $objectManager->create(\Magento\MediaStorage\Model\File\Validator\NotProtectedExtension::class); + $this->assertFalse($model->isValid($extension)); + } + + public function isValidDataProvider() + { + return [ + ['phpt'], + ['pht'] + ]; + } +} From 1c61c43a93470dabe373353fa3e9351aa9fffc88 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Fri, 12 Oct 2018 12:08:02 -0500 Subject: [PATCH 0212/1158] MAGETWO-95234: Change regular expression --- app/code/Magento/Sales/Helper/Admin.php | 4 ++- lib/internal/Magento/Framework/Escaper.php | 34 +++++++++++++------ .../Framework/View/Element/AbstractBlock.php | 1 + 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Sales/Helper/Admin.php b/app/code/Magento/Sales/Helper/Admin.php index 22d3b76b6c920..7053a696dcab5 100644 --- a/app/code/Magento/Sales/Helper/Admin.php +++ b/app/code/Magento/Sales/Helper/Admin.php @@ -193,7 +193,9 @@ private function filterUrl(string $url): string if ($urlScheme !== 'http' && $urlScheme !== 'https') { $url = null; } - } else { + } + + if (!$url) { $url = '#'; } diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php index 4546de7978e5b..603c2b395462f 100644 --- a/lib/internal/Magento/Framework/Escaper.php +++ b/lib/internal/Magento/Framework/Escaper.php @@ -69,16 +69,7 @@ public function escapeHtml($data, $allowedTags = null) } } elseif (strlen($data)) { if (is_array($allowedTags) && !empty($allowedTags)) { - $notAllowedTags = array_intersect( - array_map('strtolower', $allowedTags), - $this->notAllowedTags - ); - if (!empty($notAllowedTags)) { - $this->getLogger()->critical( - 'The following tag(s) are not allowed: ' . implode(', ', $notAllowedTags) - ); - $allowedTags = array_diff($allowedTags, $this->notAllowedTags); - } + $allowedTags = $this->filterProhibitedTags($allowedTags); $wrapperElementId = uniqid(); $domDocument = new \DOMDocument('1.0', 'UTF-8'); set_error_handler( @@ -378,4 +369,27 @@ private function getLogger() } return $this->logger; } + + /** + * Filter prohibited tags. + * + * @param array $allowedTags + * @return array + */ + private function filterProhibitedTags(array $allowedTags): array + { + $notAllowedTags = array_intersect( + array_map('strtolower', $allowedTags), + $this->notAllowedTags + ); + + if (!empty($notAllowedTags)) { + $this->getLogger()->critical( + 'The following tag(s) are not allowed: ' . implode(', ', $notAllowedTags) + ); + $allowedTags = array_diff($allowedTags, $this->notAllowedTags); + } + + return $allowedTags; + } } diff --git a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php index 3f88504f051e0..335006555d2f1 100644 --- a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php +++ b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php @@ -1156,6 +1156,7 @@ public function getVar($name, $module = null) /** * Determine if the block scope is private or public. + * * Returns true if scope is private, false otherwise * * @return bool From b68802f2a07b342a56a36a74ff7383975f42332c Mon Sep 17 00:00:00 2001 From: pganapat <prabhuramgr28493@gmail.com> Date: Fri, 12 Oct 2018 15:08:56 -0500 Subject: [PATCH 0213/1158] MAGETWO-95213: Updating Product Status With Mass Action By Scope Updates The Default Value - Modified store_id validation to take in store_id from filters, when store is null in params. --- .../Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php index b7655f7ee2862..83278ca78c738 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php @@ -87,7 +87,7 @@ public function execute() $filterRequest = $this->getRequest()->getParam('filters', null); $status = (int) $this->getRequest()->getParam('status'); - if (null !== $storeId && null !== $filterRequest) { + if (null === $storeId && null !== $filterRequest) { $storeId = (isset($filterRequest['store_id'])) ? (int) $filterRequest['store_id'] : 0; } From ad85c9546bd06adddd908aef9cc0bb3b2346463e Mon Sep 17 00:00:00 2001 From: Matei Purcaru <matei.purcaru@gmail.com> Date: Sun, 14 Oct 2018 17:59:50 +0300 Subject: [PATCH 0214/1158] magento/graphql-ce#41: [Query] My Account > My Orders --- .../SalesGraphQl/Model/Resolver/Orders.php | 87 +++++++++++++ app/code/Magento/SalesGraphQl/README.md | 6 + app/code/Magento/SalesGraphQl/composer.json | 27 ++++ app/code/Magento/SalesGraphQl/etc/module.xml | 10 ++ .../Magento/SalesGraphQl/etc/schema.graphqls | 19 +++ .../Magento/SalesGraphQl/registration.php | 10 ++ dev/tests/api-functional/phpunit.xml.dist | 56 +++++++++ .../Magento/GraphQl/Sales/OrdersTest.php | 115 ++++++++++++++++++ .../Sales/_files/order_list_rollback.php | 2 - .../Sales/_files/orders_with_customer.php | 101 +++++++++++++++ .../_files/orders_with_customer_rollback.php | 7 ++ 11 files changed, 438 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php create mode 100644 app/code/Magento/SalesGraphQl/README.md create mode 100644 app/code/Magento/SalesGraphQl/composer.json create mode 100644 app/code/Magento/SalesGraphQl/etc/module.xml create mode 100644 app/code/Magento/SalesGraphQl/etc/schema.graphqls create mode 100644 app/code/Magento/SalesGraphQl/registration.php create mode 100644 dev/tests/api-functional/phpunit.xml.dist create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php new file mode 100644 index 0000000000000..c6c6ac6203789 --- /dev/null +++ b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SalesGraphQl\Model\Resolver; + +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface; +use Magento\CustomerGraphQl\Model\Customer\CheckCustomerAccountInterface; + +/** + * {@inheritdoc} + */ +class Orders implements ResolverInterface +{ + /** + * @var UserContextInterface + */ + private $userContext; + + /** + * @var CollectionFactoryInterface + */ + private $collectionFactory; + + /** + * @var CheckCustomerAccountInterface + */ + private $checkCustomerAccount; + + /** + * Orders constructor. + * @param UserContextInterface $userContext + * @param CollectionFactoryInterface $collectionFactory + */ + public function __construct( + UserContextInterface $userContext, + CollectionFactoryInterface $collectionFactory, + CheckCustomerAccountInterface $checkCustomerAccount + ) { + $this->userContext = $userContext; + $this->collectionFactory = $collectionFactory; + $this->checkCustomerAccount = $checkCustomerAccount; + + } + + /** + * {@inheritdoc} + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + + $customerId = $this->userContext->getUserId(); + + $this->checkCustomerAccount->execute($customerId, $this->userContext->getUserType()); + + $orders = $this->collectionFactory->create($customerId); + $items = []; + + // @TODO Add shipping & billing address in response + // @TODO Add order currency object in response + /** @var \Magento\Sales\Model\Order $order */ + foreach ($orders as $order) { + $items[] = [ + 'id' => $order->getId(), + 'increment_id' => $order->getIncrementId(), + 'created_at' => $order->getCreatedAt(), + 'grant_total' => $order->getGrandTotal(), + 'state' => $order->getState(), + 'status' => $order->getStatus() + ]; + } + + return ['items' => $items]; + } +} \ No newline at end of file diff --git a/app/code/Magento/SalesGraphQl/README.md b/app/code/Magento/SalesGraphQl/README.md new file mode 100644 index 0000000000000..d827613570bad --- /dev/null +++ b/app/code/Magento/SalesGraphQl/README.md @@ -0,0 +1,6 @@ +# SalesGraphQl + +**SalesGraphQl** provides type and resolver information for the GraphQl module +to generate sales orders information endpoints. + +Also will provides endpoints for modifying an order. diff --git a/app/code/Magento/SalesGraphQl/composer.json b/app/code/Magento/SalesGraphQl/composer.json new file mode 100644 index 0000000000000..b75e18c7b7a97 --- /dev/null +++ b/app/code/Magento/SalesGraphQl/composer.json @@ -0,0 +1,27 @@ +{ + "name": "magento/module-sales-graph-ql", + "description": "N/A", + "type": "magento2-module", + "require": { + "php": "~7.1.3||~7.2.0", + "magento/framework": "*", + "magento/module-customer": "*", + "magento/module-catalog": "*", + "magento/module-store": "*" + }, + "suggest": { + "magento/module-graph-ql": "*" + }, + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\SalesGraphQl\\": "" + } + } +} diff --git a/app/code/Magento/SalesGraphQl/etc/module.xml b/app/code/Magento/SalesGraphQl/etc/module.xml new file mode 100644 index 0000000000000..70a55db67a506 --- /dev/null +++ b/app/code/Magento/SalesGraphQl/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_SalesGraphQl"/> +</config> diff --git a/app/code/Magento/SalesGraphQl/etc/schema.graphqls b/app/code/Magento/SalesGraphQl/etc/schema.graphqls new file mode 100644 index 0000000000000..c137484cd2f65 --- /dev/null +++ b/app/code/Magento/SalesGraphQl/etc/schema.graphqls @@ -0,0 +1,19 @@ +# Copyright © Magento, Inc. All rights reserved. +# See COPYING.txt for license details. + +type Query { + customerOrders: Orders @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\Orders") @doc(description: "List of customer orders") +} + +type Order @doc(description: "Order mapping fields") { + id: Int + increment_id: String + created_at: String + grant_total: Float + state: String + status: String +} + +type Orders { + items: [Order] @doc(description: "Array of orders") +} diff --git a/app/code/Magento/SalesGraphQl/registration.php b/app/code/Magento/SalesGraphQl/registration.php new file mode 100644 index 0000000000000..afb4091bfa32f --- /dev/null +++ b/app/code/Magento/SalesGraphQl/registration.php @@ -0,0 +1,10 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Component\ComponentRegistrar; + +ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_SalesGraphQl', __DIR__); diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist new file mode 100644 index 0000000000000..c869608462d08 --- /dev/null +++ b/dev/tests/api-functional/phpunit.xml.dist @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * PHPUnit configuration for GraphQL web API functional tests. + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.2/phpunit.xsd" + colors="true" + columns="max" + beStrictAboutTestsThatDoNotTestAnything="false" + bootstrap="./framework/bootstrap.php" +> + <!-- Test suites definition --> + <testsuites> + <testsuite name="Magento GraphQL web API functional tests"> + <directory suffix="Test.php">testsuite/Magento/GraphQl</directory> + </testsuite> + </testsuites> + + <!-- PHP INI settings and constants definition --> + <php> + <includePath>./testsuite</includePath> + <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> + <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/> + <!-- Webserver URL --> + <const name="TESTS_BASE_URL" value="http://magento.inno"/> + <!-- Webserver API user --> + <const name="TESTS_WEBSERVICE_USER" value="admin"/> + <!-- Webserver API key --> + <const name="TESTS_WEBSERVICE_APIKEY" value="123123q"/> + <!-- Define if debugger should be started using XDEBUG_SESSION cookie --> + <const name="TESTS_XDEBUG_ENABLED" value="true"/> + <!-- Define XDEBUG_SESSION cookie value--> + <const name="TESTS_XDEBUG_SESSION" value="MEETMAGENTO" /> + + <ini name="date.timezone" value="America/Los_Angeles"/> + + <!-- Semicolon-separated 'glob' patterns, that match global XML configuration files --> + <const name="TESTS_GLOBAL_CONFIG_DIR" value="../../../app/etc"/> + <!-- Whether to cleanup the application before running tests or not --> + <const name="TESTS_CLEANUP" value="enabled"/> + <!--Defines if Magento should be installed before tests execution--> + <const name="TESTS_MAGENTO_INSTALLATION" value="disabled"/> + <!-- Magento mode for tests execution. Possible values are "default", "developer" and "production". --> + <const name="TESTS_MAGENTO_MODE" value="default"/> + </php> + + <!-- Test listeners --> + <listeners> + <listener class="Magento\TestFramework\Event\PhpUnit"/> + </listeners> +</phpunit> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php new file mode 100644 index 0000000000000..3a85c044f16a9 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php @@ -0,0 +1,115 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Sales; + +use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\TestFramework\TestCase\GraphQlAbstract; +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Class OrdersTest + */ +class OrdersTest extends GraphQlAbstract +{ + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; + + /** + * {@inheritdoc} + */ + protected function setUp() + { + parent::setUp(); + $objectManager = Bootstrap::getObjectManager(); + $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Sales/_files/orders_with_customer.php + */ + public function testOrdersQuery() + { + $query = + <<<QUERY +query { + customerOrders { + items { + id + increment_id + created_at + grant_total + state + status + } + } +} +QUERY; + + $currentEmail = 'customer@example.com'; + $currentPassword = 'password'; + + $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword)); + + $expectedData = [ + [ + 'increment_id' => '100000002', + 'state' => \Magento\Sales\Model\Order::STATE_NEW, + 'status' => 'processing', + 'grant_total' => 120.00 + ], + [ + 'increment_id' => '100000003', + 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, + 'status' => 'processing', + 'grant_total' => 130.00 + ], + [ + 'increment_id' => '100000004', + 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, + 'status' => 'closed', + 'grant_total' => 140.00 + ], + [ + 'increment_id' => '100000005', + 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, + 'status' => 'complete', + 'grant_total' => 150.00 + ], + [ + 'increment_id' => '100000006', + 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, + 'status' => 'complete', + 'grant_total' => 160.00 + ] + ]; + + $actualData = $response['customerOrders']['items']; + + foreach ($expectedData as $key => $data) { + $this->assertEquals($data['increment_id'], $actualData[$key]['increment_id']); + $this->assertEquals($data['grant_total'], $actualData[$key]['grant_total']); + $this->assertEquals($data['state'], $actualData[$key]['state']); + $this->assertEquals($data['status'], $actualData[$key]['status']); + } + } + + /** + * @param string $email + * @param string $password + * @return array + * @throws \Magento\Framework\Exception\AuthenticationException + */ + private function getCustomerAuthHeaders(string $email, string $password): array + { + $customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password); + return ['Authorization' => 'Bearer ' . $customerToken]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_list_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_list_rollback.php index aae4a557ba1ed..6e24cee501f51 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_list_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_list_rollback.php @@ -4,6 +4,4 @@ * See COPYING.txt for license details. */ -use Magento\Sales\Model\Order; - require 'default_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php new file mode 100644 index 0000000000000..e649396391ca9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php @@ -0,0 +1,101 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Sales\Model\Order; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order\Address as OrderAddress; + +require 'order.php'; +/** @var Order $order */ +/** @var Order\Payment $payment */ +/** @var Order\Item $orderItem */ +/** @var array $addressData Data for creating addresses for the orders. */ +$orders = [ + [ + 'increment_id' => '100000002', + 'state' => \Magento\Sales\Model\Order::STATE_NEW, + 'status' => 'processing', + 'grand_total' => 120.00, + 'subtotal' => 120.00, + 'base_grand_total' => 120.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], + [ + 'increment_id' => '100000003', + 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, + 'status' => 'processing', + 'grand_total' => 130.00, + 'base_grand_total' => 130.00, + 'subtotal' => 130.00, + 'store_id' => 0, + 'website_id' => 0, + 'payment' => $payment + ], + [ + 'increment_id' => '100000004', + 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, + 'status' => 'closed', + 'grand_total' => 140.00, + 'base_grand_total' => 140.00, + 'subtotal' => 140.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], + [ + 'increment_id' => '100000005', + 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, + 'status' => 'complete', + 'grand_total' => 150.00, + 'base_grand_total' => 150.00, + 'subtotal' => 150.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], + [ + 'increment_id' => '100000006', + 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, + 'status' => 'complete', + 'grand_total' => 160.00, + 'base_grand_total' => 160.00, + 'subtotal' => 160.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], +]; + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->create(OrderRepositoryInterface::class); +/** @var array $orderData */ +foreach ($orders as $orderData) { + /** @var $order \Magento\Sales\Model\Order */ + $order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Sales\Model\Order::class + ); + + // Reset addresses + /** @var Order\Address $billingAddress */ + $billingAddress = $objectManager->create(OrderAddress::class, ['data' => $addressData]); + $billingAddress->setAddressType('billing'); + + $shippingAddress = clone $billingAddress; + $shippingAddress->setId(null)->setAddressType('shipping'); + + $order + ->setData($orderData) + ->addItem($orderItem) + ->setCustomerIsGuest(false) + ->setCustomerId(1) + ->setCustomerEmail('customer@example.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress); + + $orderRepository->save($order); +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php new file mode 100644 index 0000000000000..6e24cee501f51 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php @@ -0,0 +1,7 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require 'default_rollback.php'; From 620d14d01365a1907f4abc19b3c50882aef86c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gheolt=CC=A6an?= <daniel.gheoltan@mindmagnetsoftware.com> Date: Sun, 14 Oct 2018 18:29:29 +0300 Subject: [PATCH 0215/1158] Binding to event collapsible scroll --- lib/web/mage/collapsible.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/web/mage/collapsible.js b/lib/web/mage/collapsible.js index 69e576bba604a..a6a1dcde6c87a 100644 --- a/lib/web/mage/collapsible.js +++ b/lib/web/mage/collapsible.js @@ -63,6 +63,12 @@ define([ this.icons = true; } + this.element.on('dimensionsChanged',function(e) { + if(e.target && e.target.classList.contains('active')) { + this._scrollToTopIfVisible(e.target); + } + }.bind(this)); + this._bind('click'); this._trigger('created'); }, @@ -453,9 +459,6 @@ define([ if (this.options.animate) { this._animate(showProps); } else { - if (this.content.length) { - this._scrollToTopIfVisible(this.content.get(0).parentElement); - } this.content.show(); } this._open(); From 087257703657d85bf06a9cf78f9efc80151389eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gheolt=CC=A6an?= <daniel.gheoltan@mindmagnetsoftware.com> Date: Sun, 14 Oct 2018 18:45:52 +0300 Subject: [PATCH 0216/1158] Binding to event collapsible scroll --- lib/web/mage/collapsible.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web/mage/collapsible.js b/lib/web/mage/collapsible.js index a6a1dcde6c87a..3d283d102e323 100644 --- a/lib/web/mage/collapsible.js +++ b/lib/web/mage/collapsible.js @@ -63,8 +63,8 @@ define([ this.icons = true; } - this.element.on('dimensionsChanged',function(e) { - if(e.target && e.target.classList.contains('active')) { + this.element.on('dimensionsChanged', function (e) { + if (e.target && e.target.classList.contains('active')) { this._scrollToTopIfVisible(e.target); } }.bind(this)); From 3f9784e3ee8c4b1f1e9df0a47ad91a6e4628024b Mon Sep 17 00:00:00 2001 From: Ian <i.cassidy@ctidigital.com> Date: Mon, 15 Oct 2018 13:38:33 +0100 Subject: [PATCH 0217/1158] 18615 updates structure for last_trans_id to be varchar 255 which is inline with klarna_core_order order_id and amazon_sales_order amazon_order_reference_id. Limit was 32 characters where as a klarna_order reference is 36 characters at present --- app/code/Magento/Sales/etc/db_schema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/etc/db_schema.xml b/app/code/Magento/Sales/etc/db_schema.xml index fda6e75cf00c6..452247e545144 100644 --- a/app/code/Magento/Sales/etc/db_schema.xml +++ b/app/code/Magento/Sales/etc/db_schema.xml @@ -663,7 +663,7 @@ <column xsi:type="varchar" name="cc_ss_start_month" nullable="true" length="128" comment="Cc Ss Start Month"/> <column xsi:type="varchar" name="echeck_account_type" nullable="true" length="255" comment="Echeck Account Type"/> - <column xsi:type="varchar" name="last_trans_id" nullable="true" length="32" comment="Last Trans Id"/> + <column xsi:type="varchar" name="last_trans_id" nullable="true" length="255" comment="Last Trans Id"/> <column xsi:type="varchar" name="cc_cid_status" nullable="true" length="32" comment="Cc Cid Status"/> <column xsi:type="varchar" name="cc_owner" nullable="true" length="128" comment="Cc Owner"/> <column xsi:type="varchar" name="cc_type" nullable="true" length="32" comment="Cc Type"/> From 3b1c5a8152e00fc89948b0a9727cde542eda8ffc Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Fri, 12 Oct 2018 14:27:24 -0500 Subject: [PATCH 0218/1158] MAGETWO-95549: Adding restriction for controller --- .../Adminhtml/Wysiwyg/Images/DeleteFiles.php | 5 ++-- .../Wysiwyg/Images/DeleteFilesTest.php | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php index 890c9bf5eae52..6f57efad41e75 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php @@ -6,11 +6,12 @@ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\Action\HttpPostActionInterface; /** * Delete image files. */ -class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images +class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images implements HttpPostActionInterface { /** * @var \Magento\Framework\Controller\Result\JsonFactory @@ -79,7 +80,7 @@ public function execute() $filesystem = $this->_objectManager->get(\Magento\Framework\Filesystem::class); $dir = $filesystem->getDirectoryRead(DirectoryList::MEDIA); $filePath = $path . '/' . \Magento\Framework\File\Uploader::getCorrectFileName($file); - if ($dir->isFile($dir->getRelativePath($filePath))) { + if ($dir->isFile($dir->getRelativePath($filePath)) && !preg_match('#.htaccess#', $file)) { $this->getStorage()->deleteFile($filePath); } } diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php index fa49a7b1f57e1..1fc07d32c77b9 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php @@ -64,6 +64,10 @@ protected function setUp() $filePath = $this->fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName; $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); copy($fixtureDir . '/' . $this->fileName, $filePath); + $path = $this->fullDirectoryPath . '/.htaccess'; + if (!$this->mediaDirectory->isFile($path)) { + $this->mediaDirectory->writeFile($path, "Order deny,allow\nDeny from all"); + } $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles::class); } @@ -87,6 +91,26 @@ public function testExecute() ); } + /** + * Check that htaccess file couldn't be removed via + * \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles::execute method + * + * @return void + */ + public function testDeleteHtaccess() + { + $this->model->getRequest()->setMethod('POST') + ->setPostValue('files', [$this->imagesHelper->idEncode('.htaccess')]); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->execute(); + + $this->assertTrue( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . '/' . '.htaccess') + ) + ); + } + /** * Execute method with traversal file path to check that there is no ability to remove file which is not * under media directory. From 75cb72f775869c7ffcca12deb20b917eb7bf74b9 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 15 Oct 2018 09:45:05 -0500 Subject: [PATCH 0219/1158] MAGETWO-95234: Change regular expression --- lib/internal/Magento/Framework/Escaper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php index 603c2b395462f..2fdf17fd2337c 100644 --- a/lib/internal/Magento/Framework/Escaper.php +++ b/lib/internal/Magento/Framework/Escaper.php @@ -373,7 +373,7 @@ private function getLogger() /** * Filter prohibited tags. * - * @param array $allowedTags + * @param string[] $allowedTags * @return array */ private function filterProhibitedTags(array $allowedTags): array From 4f469a06bd217cdee87eeff33d7a3462e2750b80 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 15 Oct 2018 09:49:59 -0500 Subject: [PATCH 0220/1158] MAGETWO-95234: Change regular expression --- lib/internal/Magento/Framework/Escaper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php index 2fdf17fd2337c..80979c3db0910 100644 --- a/lib/internal/Magento/Framework/Escaper.php +++ b/lib/internal/Magento/Framework/Escaper.php @@ -374,7 +374,7 @@ private function getLogger() * Filter prohibited tags. * * @param string[] $allowedTags - * @return array + * @return string[] */ private function filterProhibitedTags(array $allowedTags): array { From f5b59b8bb89ee6c7440d1ea60d7ae68387445e5d Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 15 Oct 2018 10:13:50 -0500 Subject: [PATCH 0221/1158] MAGETWO-95642: Import error --- .../Test/Unit/Model/Entity/AttributeTest.php | 4 +++ .../ImportExport/Model/Import/Source/Zip.php | 7 ++++ .../Test/Unit/Model/ProblemTest.php | 28 ++++++++++++++++ .../Magento/Framework/Archive/Zip.php | 33 ++++++++++++++----- 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeTest.php index b15174960524c..402497a1379c0 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Eav\Test\Unit\Model\Entity; +/** + * Class AttributeTest. + */ class AttributeTest extends \PHPUnit\Framework\TestCase { /** @@ -128,6 +131,7 @@ public function testGetFrontendLabels() $attributeId = 1; $storeLabels = ['test_attribute_store1']; $frontendLabelFactory = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\FrontendLabelFactory::class) + ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); $resource = $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute::class) diff --git a/app/code/Magento/ImportExport/Model/Import/Source/Zip.php b/app/code/Magento/ImportExport/Model/Import/Source/Zip.php index b7fafc43ca4ed..7c13e47957cda 100644 --- a/app/code/Magento/ImportExport/Model/Import/Source/Zip.php +++ b/app/code/Magento/ImportExport/Model/Import/Source/Zip.php @@ -5,6 +5,8 @@ */ namespace Magento\ImportExport\Model\Import\Source; +use Magento\Framework\Exception\ValidatorException; + /** * Zip import adapter. */ @@ -14,6 +16,8 @@ class Zip extends Csv * @param string $file * @param \Magento\Framework\Filesystem\Directory\Write $directory * @param string $options + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\ValidatorException */ public function __construct( $file, @@ -25,6 +29,9 @@ public function __construct( $directory->getRelativePath($file), $directory->getRelativePath(preg_replace('/\.zip$/i', '.csv', $file)) ); + if (!$file) { + throw new ValidatorException(__('Sorry, but the data is invalid or the file is not uploaded.')); + } parent::__construct($file, $directory, $options); } } diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/ProblemTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/ProblemTest.php index 889fc11d71d7e..8ee6de1e44476 100644 --- a/app/code/Magento/Newsletter/Test/Unit/Model/ProblemTest.php +++ b/app/code/Magento/Newsletter/Test/Unit/Model/ProblemTest.php @@ -17,6 +17,9 @@ use Magento\Newsletter\Model\Subscriber; use Magento\Newsletter\Model\SubscriberFactory; +/** + * Class ProblemTest + */ class ProblemTest extends \PHPUnit\Framework\TestCase { /** @@ -59,6 +62,9 @@ class ProblemTest extends \PHPUnit\Framework\TestCase */ private $problemModel; + /** + * @inheritdoc + */ protected function setUp() { $this->contextMock = $this->getMockBuilder(Context::class) @@ -68,6 +74,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); $this->subscriberFactoryMock = $this->getMockBuilder(SubscriberFactory::class) + ->disableOriginalConstructor() ->getMock(); $this->subscriberMock = $this->getMockBuilder(Subscriber::class) ->disableOriginalConstructor() @@ -98,6 +105,9 @@ protected function setUp() ); } + /** + * @return void + */ public function testAddSubscriberData() { $subscriberId = 1; @@ -111,6 +121,9 @@ public function testAddSubscriberData() self::assertEquals($subscriberId, $this->problemModel->getSubscriberId()); } + /** + * @return void + */ public function testAddQueueData() { $queueId = 1; @@ -127,6 +140,9 @@ public function testAddQueueData() self::assertEquals($queueId, $this->problemModel->getQueueId()); } + /** + * @return void + */ public function testAddErrorData() { $exceptionMessage = 'Some message'; @@ -140,17 +156,26 @@ public function testAddErrorData() self::assertEquals($exceptionCode, $this->problemModel->getProblemErrorCode()); } + /** + * @return void + */ public function testGetSubscriberWithNoSubscriberId() { self::assertNull($this->problemModel->getSubscriber()); } + /** + * @return void + */ public function testGetSubscriber() { $this->setSubscriber(); self::assertEquals($this->subscriberMock, $this->problemModel->getSubscriber()); } + /** + * @return void + */ public function testUnsubscribeWithNoSubscriber() { $this->subscriberMock->expects($this->never()) @@ -162,6 +187,9 @@ public function testUnsubscribeWithNoSubscriber() self::assertEquals($this->problemModel, $result); } + /** + * @return void + */ public function testUnsubscribe() { $this->setSubscriber(); diff --git a/lib/internal/Magento/Framework/Archive/Zip.php b/lib/internal/Magento/Framework/Archive/Zip.php index f33ad8700f056..908b045c15397 100644 --- a/lib/internal/Magento/Framework/Archive/Zip.php +++ b/lib/internal/Magento/Framework/Archive/Zip.php @@ -4,13 +4,11 @@ * See COPYING.txt for license details. */ -/** - * Class to work with zip archives - * - * @author Magento Core Team <core@magentocommerce.com> - */ namespace Magento\Framework\Archive; +/** + * Zip compressed file archive. + */ class Zip extends AbstractArchive implements ArchiveInterface { /** @@ -55,10 +53,29 @@ public function unpack($source, $destination) { $zip = new \ZipArchive(); $zip->open($source); - $filename = $zip->getNameIndex(0); - $zip->extractTo(dirname($destination), $filename); - rename(dirname($destination).'/'.$filename, $destination); + $filename = $this->filterRelativePaths($zip->getNameIndex(0) ?: ''); + if ($filename) { + $zip->extractTo(dirname($destination), $filename); + rename(dirname($destination).'/'.$filename, $destination); + } else { + $destination = ''; + } $zip->close(); return $destination; } + + /** + * Filter file names with relative paths. + * + * @param string $path + * @return string + */ + private function filterRelativePaths(string $path): string + { + if ($path && preg_match('#^\s*(../)|(/../)#i', $path)) { + $path = ''; + } + + return $path; + } } From 584eb7d6c876ea8c20e8a032ebddb43f5f8d3553 Mon Sep 17 00:00:00 2001 From: Matei Purcaru <matei.purcaru@gmail.com> Date: Mon, 15 Oct 2018 19:46:32 +0300 Subject: [PATCH 0222/1158] magento/graphql-ce#41: Fixed typos --- .../SalesGraphQl/Model/Resolver/Orders.php | 4 +- app/code/Magento/SalesGraphQl/README.md | 4 +- .../Magento/SalesGraphQl/etc/schema.graphqls | 11 ++-- dev/tests/api-functional/phpunit.xml.dist | 56 ------------------- .../Magento/GraphQl/Sales/OrdersTest.php | 12 ++-- 5 files changed, 13 insertions(+), 74 deletions(-) delete mode 100644 dev/tests/api-functional/phpunit.xml.dist diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php index c6c6ac6203789..91078c1580634 100644 --- a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php +++ b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php @@ -68,15 +68,13 @@ public function resolve( $orders = $this->collectionFactory->create($customerId); $items = []; - // @TODO Add shipping & billing address in response - // @TODO Add order currency object in response /** @var \Magento\Sales\Model\Order $order */ foreach ($orders as $order) { $items[] = [ 'id' => $order->getId(), 'increment_id' => $order->getIncrementId(), 'created_at' => $order->getCreatedAt(), - 'grant_total' => $order->getGrandTotal(), + 'grand_total' => $order->getGrandTotal(), 'state' => $order->getState(), 'status' => $order->getStatus() ]; diff --git a/app/code/Magento/SalesGraphQl/README.md b/app/code/Magento/SalesGraphQl/README.md index d827613570bad..d5717821b164c 100644 --- a/app/code/Magento/SalesGraphQl/README.md +++ b/app/code/Magento/SalesGraphQl/README.md @@ -1,6 +1,4 @@ # SalesGraphQl **SalesGraphQl** provides type and resolver information for the GraphQl module -to generate sales orders information endpoints. - -Also will provides endpoints for modifying an order. +to generate sales orders information. diff --git a/app/code/Magento/SalesGraphQl/etc/schema.graphqls b/app/code/Magento/SalesGraphQl/etc/schema.graphqls index c137484cd2f65..44f106532858f 100644 --- a/app/code/Magento/SalesGraphQl/etc/schema.graphqls +++ b/app/code/Magento/SalesGraphQl/etc/schema.graphqls @@ -2,18 +2,17 @@ # See COPYING.txt for license details. type Query { - customerOrders: Orders @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\Orders") @doc(description: "List of customer orders") + customerOrders: CustomerOrders @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\Orders") @doc(description: "List of customer orders") } -type Order @doc(description: "Order mapping fields") { +type CustomerOrder @doc(description: "Order mapping fields") { id: Int increment_id: String created_at: String - grant_total: Float - state: String + grand_total: Float status: String } -type Orders { - items: [Order] @doc(description: "Array of orders") +type CustomerOrders { + items: [CustomerOrder] @doc(description: "Array of orders") } diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist deleted file mode 100644 index c869608462d08..0000000000000 --- a/dev/tests/api-functional/phpunit.xml.dist +++ /dev/null @@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * PHPUnit configuration for GraphQL web API functional tests. - * - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.2/phpunit.xsd" - colors="true" - columns="max" - beStrictAboutTestsThatDoNotTestAnything="false" - bootstrap="./framework/bootstrap.php" -> - <!-- Test suites definition --> - <testsuites> - <testsuite name="Magento GraphQL web API functional tests"> - <directory suffix="Test.php">testsuite/Magento/GraphQl</directory> - </testsuite> - </testsuites> - - <!-- PHP INI settings and constants definition --> - <php> - <includePath>./testsuite</includePath> - <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> - <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/> - <!-- Webserver URL --> - <const name="TESTS_BASE_URL" value="http://magento.inno"/> - <!-- Webserver API user --> - <const name="TESTS_WEBSERVICE_USER" value="admin"/> - <!-- Webserver API key --> - <const name="TESTS_WEBSERVICE_APIKEY" value="123123q"/> - <!-- Define if debugger should be started using XDEBUG_SESSION cookie --> - <const name="TESTS_XDEBUG_ENABLED" value="true"/> - <!-- Define XDEBUG_SESSION cookie value--> - <const name="TESTS_XDEBUG_SESSION" value="MEETMAGENTO" /> - - <ini name="date.timezone" value="America/Los_Angeles"/> - - <!-- Semicolon-separated 'glob' patterns, that match global XML configuration files --> - <const name="TESTS_GLOBAL_CONFIG_DIR" value="../../../app/etc"/> - <!-- Whether to cleanup the application before running tests or not --> - <const name="TESTS_CLEANUP" value="enabled"/> - <!--Defines if Magento should be installed before tests execution--> - <const name="TESTS_MAGENTO_INSTALLATION" value="disabled"/> - <!-- Magento mode for tests execution. Possible values are "default", "developer" and "production". --> - <const name="TESTS_MAGENTO_MODE" value="default"/> - </php> - - <!-- Test listeners --> - <listeners> - <listener class="Magento\TestFramework\Event\PhpUnit"/> - </listeners> -</phpunit> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php index 3a85c044f16a9..ef7ceebc3a053 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php @@ -63,31 +63,31 @@ public function testOrdersQuery() 'increment_id' => '100000002', 'state' => \Magento\Sales\Model\Order::STATE_NEW, 'status' => 'processing', - 'grant_total' => 120.00 + 'grand_total' => 120.00 ], [ 'increment_id' => '100000003', 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, 'status' => 'processing', - 'grant_total' => 130.00 + 'grand_total' => 130.00 ], [ 'increment_id' => '100000004', 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, 'status' => 'closed', - 'grant_total' => 140.00 + 'grand_total' => 140.00 ], [ 'increment_id' => '100000005', 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, 'status' => 'complete', - 'grant_total' => 150.00 + 'grand_total' => 150.00 ], [ 'increment_id' => '100000006', 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, 'status' => 'complete', - 'grant_total' => 160.00 + 'grand_total' => 160.00 ] ]; @@ -95,7 +95,7 @@ public function testOrdersQuery() foreach ($expectedData as $key => $data) { $this->assertEquals($data['increment_id'], $actualData[$key]['increment_id']); - $this->assertEquals($data['grant_total'], $actualData[$key]['grant_total']); + $this->assertEquals($data['grand_total'], $actualData[$key]['grand_total']); $this->assertEquals($data['state'], $actualData[$key]['state']); $this->assertEquals($data['status'], $actualData[$key]['status']); } From 4a31f4f11972bf69fdbbe125fd262f9dfdfed0de Mon Sep 17 00:00:00 2001 From: Matei Purcaru <matei.purcaru@gmail.com> Date: Mon, 15 Oct 2018 19:55:48 +0300 Subject: [PATCH 0223/1158] magento/graphql-ce#41: get user info from resolver context --- .../SalesGraphQl/Model/Resolver/Orders.php | 29 +++++++------------ .../Magento/GraphQl/Sales/OrdersTest.php | 23 +++++---------- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php index 91078c1580634..05af6829de454 100644 --- a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php +++ b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php @@ -15,15 +15,10 @@ use Magento\CustomerGraphQl\Model\Customer\CheckCustomerAccountInterface; /** - * {@inheritdoc} + * Class Orders */ class Orders implements ResolverInterface { - /** - * @var UserContextInterface - */ - private $userContext; - /** * @var CollectionFactoryInterface */ @@ -36,15 +31,13 @@ class Orders implements ResolverInterface /** * Orders constructor. - * @param UserContextInterface $userContext * @param CollectionFactoryInterface $collectionFactory + * @param CheckCustomerAccountInterface $checkCustomerAccount */ public function __construct( - UserContextInterface $userContext, CollectionFactoryInterface $collectionFactory, CheckCustomerAccountInterface $checkCustomerAccount ) { - $this->userContext = $userContext; $this->collectionFactory = $collectionFactory; $this->checkCustomerAccount = $checkCustomerAccount; @@ -55,18 +48,17 @@ public function __construct( */ public function resolve( Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null + $context, + ResolveInfo $info, + array $value = null, + array $args = null ) { + $customerId = $context->getUserId(); - $customerId = $this->userContext->getUserId(); + $this->checkCustomerAccount->execute($customerId, $context->getUserType()); - $this->checkCustomerAccount->execute($customerId, $this->userContext->getUserType()); - - $orders = $this->collectionFactory->create($customerId); $items = []; + $orders = $this->collectionFactory->create($customerId); /** @var \Magento\Sales\Model\Order $order */ foreach ($orders as $order) { @@ -75,11 +67,10 @@ public function resolve( 'increment_id' => $order->getIncrementId(), 'created_at' => $order->getCreatedAt(), 'grand_total' => $order->getGrandTotal(), - 'state' => $order->getState(), 'status' => $order->getStatus() ]; } return ['items' => $items]; } -} \ No newline at end of file +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php index ef7ceebc3a053..33620f6e55386 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php @@ -40,16 +40,15 @@ public function testOrdersQuery() $query = <<<QUERY query { - customerOrders { - items { - id - increment_id - created_at - grant_total - state - status - } + customerOrders { + items { + id + increment_id + created_at + grand_total + status } + } } QUERY; @@ -61,31 +60,26 @@ public function testOrdersQuery() $expectedData = [ [ 'increment_id' => '100000002', - 'state' => \Magento\Sales\Model\Order::STATE_NEW, 'status' => 'processing', 'grand_total' => 120.00 ], [ 'increment_id' => '100000003', - 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, 'status' => 'processing', 'grand_total' => 130.00 ], [ 'increment_id' => '100000004', - 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, 'status' => 'closed', 'grand_total' => 140.00 ], [ 'increment_id' => '100000005', - 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, 'status' => 'complete', 'grand_total' => 150.00 ], [ 'increment_id' => '100000006', - 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, 'status' => 'complete', 'grand_total' => 160.00 ] @@ -96,7 +90,6 @@ public function testOrdersQuery() foreach ($expectedData as $key => $data) { $this->assertEquals($data['increment_id'], $actualData[$key]['increment_id']); $this->assertEquals($data['grand_total'], $actualData[$key]['grand_total']); - $this->assertEquals($data['state'], $actualData[$key]['state']); $this->assertEquals($data['status'], $actualData[$key]['status']); } } From 94f25c3ba8dffb00ab31c3cdc9a6262b42fabee6 Mon Sep 17 00:00:00 2001 From: pganapat <prabhuramgr28493@gmail.com> Date: Mon, 15 Oct 2018 12:17:26 -0500 Subject: [PATCH 0224/1158] MAGETWO-95213: Updating Product Status With Mass Action By Scope Updates The Default Value - Added short class description. --- .../Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php index 83278ca78c738..9d7273fb3f23c 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php @@ -14,6 +14,7 @@ use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; /** + * Updates status for a batch of products. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class MassStatus extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface From 0f1f83e66a9b20b4d100fcda84b5a38c21d8c828 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Mon, 15 Oct 2018 13:06:43 -0500 Subject: [PATCH 0225/1158] MAGETWO-95505: Broken Swagger markup --- .../Swagger/view/frontend/templates/swagger-ui/index.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml index 4e1b50723782a..26ef4847a1267 100644 --- a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml +++ b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml @@ -17,7 +17,7 @@ * @codingStandardsIgnoreFile */ -$schemaUrl = $block->escapeUrl($block->getSchemaUrl()); +$schemaUrl = $block->getSchemaUrl(); ?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0"> @@ -58,7 +58,7 @@ $schemaUrl = $block->escapeUrl($block->getSchemaUrl()); <div class="swagger-ui-wrap"> <a id="logo" href="http://swagger.io">swagger</a> <form id='api_selector'> - <input id="input_baseUrl" type="hidden" value="<?= /* @escapeNotVerified */ $schemaUrl ?>"/> + <input id="input_baseUrl" type="hidden" value="<?= $block->escapeUrl($schemaUrl) ?>"/> <div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div> <div class='input'><a id="explore" href="#" data-sw-translate>apply</a></div> </form> From 56931215d1b2ae9b2a85a0a18e49d9727063a702 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Fri, 12 Oct 2018 15:37:09 -0500 Subject: [PATCH 0226/1158] MAGETWO-95391: Widget Escaping - Convert widget code to heredoc and escape output --- .../Magento/Widget/Block/Adminhtml/Widget.php | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget.php b/app/code/Magento/Widget/Block/Adminhtml/Widget.php index e4854415d7534..16280a5a061cd 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget.php @@ -40,13 +40,17 @@ protected function _construct() $this->buttonList->update('reset', 'label', __('Cancel')); $this->buttonList->update('reset', 'onclick', 'wWidget.closeModal()'); - $this->_formScripts[] = 'require(["mage/adminhtml/wysiwyg/widget"],' - . ' function(){wWidget = new WysiwygWidget.Widget(' - . '"widget_options_form", "select_widget_type", "widget_options", "' - . $this->getUrl( - 'adminhtml/*/loadOptions' - ) . '", "' . $this->getRequest()->getParam( - 'widget_target_id' - ) . '");});'; + $this->_formScripts[] = <<<EOJS +require(['mage/adminhtml/wysiwyg/widget'], function() { + wWidget = new WysiwygWidget.Widget( + 'widget_options_form', + 'select_widget_type', + 'widget_options', + '{$this->getUrl('adminhtml/*/loadOptions')}', + '{$this->escapeJs($this->getRequest()->getParam('widget_target_id'))}' + ); +}); +EOJS; + } } From f722280905f8e5a510e9b0c202e12b37de7e14a2 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Mon, 15 Oct 2018 14:16:39 -0500 Subject: [PATCH 0227/1158] MAGETWO-95391: Widget Escaping - Resolve static test failures --- app/code/Magento/Widget/Block/Adminhtml/Widget.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget.php b/app/code/Magento/Widget/Block/Adminhtml/Widget.php index 16280a5a061cd..dad318f163b4b 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget.php @@ -15,7 +15,7 @@ class Widget extends \Magento\Backend\Block\Widget\Form\Container { /** - * @return void + * @inheritdoc */ protected function _construct() { @@ -51,6 +51,5 @@ protected function _construct() ); }); EOJS; - } } From 954ee4fbecf96d3898bbad21d46f2430d6ebd544 Mon Sep 17 00:00:00 2001 From: Ayaz Mittaqi <ayaz.mittaqi024@webkul.com> Date: Tue, 16 Oct 2018 02:51:20 +0530 Subject: [PATCH 0228/1158] fixed issue regarding referer url of compare page during adding product to wishlist. --- .../Magento/Catalog/Block/Product/Compare/ListCompare.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php b/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php index 6c54aa4e171ef..76f5dbd1bea88 100644 --- a/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php +++ b/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php @@ -122,12 +122,7 @@ public function __construct( */ public function getAddToWishlistParams($product) { - $continueUrl = $this->urlEncoder->encode($this->getUrl('customer/account')); - $urlParamName = Action::PARAM_NAME_URL_ENCODED; - - $continueUrlParams = [$urlParamName => $continueUrl]; - - return $this->_wishlistHelper->getAddParams($product, $continueUrlParams); + return $this->_wishlistHelper->getAddParams($product); } /** From 12b7e08c2f262d0683e5b61d5fd2487aac19c27d Mon Sep 17 00:00:00 2001 From: Fabian Schmengler <fs@integer-net.de> Date: Tue, 16 Oct 2018 09:21:09 +0200 Subject: [PATCH 0229/1158] Set cache id prefix on installation --- .../Setup/Model/ConfigOptionsList/Cache.php | 23 ++++++ .../Model/ConfigOptionsList/PageCache.php | 23 ++++++ .../Model/ConfigOptionsList/CacheTest.php | 70 +++++++++++++++++- .../Model/ConfigOptionsList/PageCacheTest.php | 71 ++++++++++++++++++- 4 files changed, 181 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php index 2f19f010c1704..85c0e2c4e9b3b 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php @@ -27,12 +27,14 @@ class Cache implements ConfigOptionsListInterface const INPUT_KEY_CACHE_BACKEND_REDIS_DATABASE = 'cache-backend-redis-db'; const INPUT_KEY_CACHE_BACKEND_REDIS_PORT = 'cache-backend-redis-port'; const INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD = 'cache-backend-redis-password'; + const INPUT_KEY_CACHE_ID_PREFIX = 'cache-id-prefix'; const CONFIG_PATH_CACHE_BACKEND = 'cache/frontend/default/backend'; const CONFIG_PATH_CACHE_BACKEND_SERVER = 'cache/frontend/default/backend_options/server'; const CONFIG_PATH_CACHE_BACKEND_DATABASE = 'cache/frontend/default/backend_options/database'; const CONFIG_PATH_CACHE_BACKEND_PORT = 'cache/frontend/default/backend_options/port'; const CONFIG_PATH_CACHE_BACKEND_PASSWORD = 'cache/frontend/default/backend_options/password'; + const CONFIG_PATH_CACHE_ID_PREFIX = 'cache/frontend/default/id_prefix'; /** * @var array @@ -112,6 +114,12 @@ public function getOptions() TextConfigOption::FRONTEND_WIZARD_TEXT, self::CONFIG_PATH_CACHE_BACKEND_PASSWORD, 'Redis server password' + ), + new TextConfigOption( + self::INPUT_KEY_CACHE_ID_PREFIX, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_CACHE_ID_PREFIX, + 'ID prefix for cache keys' ) ]; } @@ -122,6 +130,11 @@ public function getOptions() public function createConfig(array $options, DeploymentConfig $deploymentConfig) { $configData = new ConfigData(ConfigFilePool::APP_ENV); + if (isset($options[self::INPUT_KEY_CACHE_ID_PREFIX])) { + $configData->set(self::CONFIG_PATH_CACHE_ID_PREFIX, $options[self::INPUT_KEY_CACHE_ID_PREFIX]); + } else { + $configData->set(self::CONFIG_PATH_CACHE_ID_PREFIX, $this->generateCachePrefix()); + } if (isset($options[self::INPUT_KEY_CACHE_BACKEND])) { if ($options[self::INPUT_KEY_CACHE_BACKEND] == self::INPUT_VALUE_CACHE_REDIS) { @@ -241,4 +254,14 @@ private function getDefaultConfigValue($inputKey) return ''; } } + + /** + * Generate default cache ID prefix based on installation dir + * + * @return string + */ + private function generateCachePrefix(): string + { + return substr(\md5(dirname(__DIR__, 6)), 0, 3) . '_'; + } } diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php index c288b4dd51d65..35a9955aad506 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php @@ -28,6 +28,7 @@ class PageCache implements ConfigOptionsListInterface const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PORT = 'page-cache-redis-port'; const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_COMPRESS_DATA = 'page-cache-redis-compress-data'; const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD = 'page-cache-redis-password'; + const INPUT_KEY_PAGE_CACHE_ID_PREFIX = 'page-cache-id-prefix'; const CONFIG_PATH_PAGE_CACHE_BACKEND = 'cache/frontend/page_cache/backend'; const CONFIG_PATH_PAGE_CACHE_BACKEND_SERVER = 'cache/frontend/page_cache/backend_options/server'; @@ -35,6 +36,7 @@ class PageCache implements ConfigOptionsListInterface const CONFIG_PATH_PAGE_CACHE_BACKEND_PORT = 'cache/frontend/page_cache/backend_options/port'; const CONFIG_PATH_PAGE_CACHE_BACKEND_COMPRESS_DATA = 'cache/frontend/page_cache/backend_options/compress_data'; const CONFIG_PATH_PAGE_CACHE_BACKEND_PASSWORD = 'cache/frontend/page_cache/backend_options/password'; + const CONFIG_PATH_PAGE_CACHE_ID_PREFIX = 'cache/frontend/page_cache/id_prefix'; /** * @var array @@ -122,6 +124,12 @@ public function getOptions() TextConfigOption::FRONTEND_WIZARD_TEXT, self::CONFIG_PATH_PAGE_CACHE_BACKEND_PASSWORD, 'Redis server password' + ), + new TextConfigOption( + self::INPUT_KEY_PAGE_CACHE_ID_PREFIX, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_PAGE_CACHE_ID_PREFIX, + 'ID prefix for cache keys' ) ]; } @@ -132,6 +140,11 @@ public function getOptions() public function createConfig(array $options, DeploymentConfig $deploymentConfig) { $configData = new ConfigData(ConfigFilePool::APP_ENV); + if (isset($options[self::INPUT_KEY_PAGE_CACHE_ID_PREFIX])) { + $configData->set(self::CONFIG_PATH_PAGE_CACHE_ID_PREFIX, $options[self::INPUT_KEY_PAGE_CACHE_ID_PREFIX]); + } else { + $configData->set(self::CONFIG_PATH_PAGE_CACHE_ID_PREFIX, $this->generateCachePrefix()); + } if (isset($options[self::INPUT_KEY_PAGE_CACHE_BACKEND])) { if ($options[self::INPUT_KEY_PAGE_CACHE_BACKEND] == self::INPUT_VALUE_PAGE_CACHE_REDIS) { @@ -252,4 +265,14 @@ private function getDefaultConfigValue($inputKey) return ''; } } + + /** + * Generate default cache ID prefix based on installation dir + * + * @return string + */ + private function generateCachePrefix(): string + { + return substr(\md5(dirname(__DIR__, 6)), 0, 3) . '_'; + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php index 1bbd2e671e59a..9c123fcb330dd 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php @@ -45,7 +45,7 @@ protected function setUp() public function testGetOptions() { $options = $this->configOptionsList->getOptions(); - $this->assertCount(5, $options); + $this->assertCount(6, $options); $this->assertArrayHasKey(0, $options); $this->assertInstanceOf(SelectConfigOption::class, $options[0]); @@ -66,6 +66,10 @@ public function testGetOptions() $this->assertArrayHasKey(4, $options); $this->assertInstanceOf(TextConfigOption::class, $options[4]); $this->assertEquals('cache-backend-redis-password', $options[4]->getName()); + + $this->assertArrayHasKey(5, $options); + $this->assertInstanceOf(TextConfigOption::class, $options[5]); + $this->assertEquals('cache-id-prefix', $options[5]->getName()); } /** @@ -85,7 +89,8 @@ public function testCreateConfigCacheRedis() 'port' => '', 'database' => '', 'password' => '' - ] + ], + 'id_prefix' => $this->expectedIdPrefix(), ] ] ] @@ -111,7 +116,8 @@ public function testCreateConfigWithRedisConfig() 'port' => '1234', 'database' => '5', 'password' => '' - ] + ], + 'id_prefix' => $this->expectedIdPrefix(), ] ] ] @@ -128,6 +134,54 @@ public function testCreateConfigWithRedisConfig() $this->assertEquals($expectedConfigData, $configData->getData()); } + /** + * testCreateConfigCacheRedis + */ + public function testCreateConfigWithFileCache() + { + $this->deploymentConfigMock->method('get')->willReturn(''); + + $expectedConfigData = [ + 'cache' => [ + 'frontend' => [ + 'default' => [ + 'id_prefix' => $this->expectedIdPrefix(), + ] + ] + ] + ]; + + $configData = $this->configOptionsList->createConfig([], $this->deploymentConfigMock); + + $this->assertEquals($expectedConfigData, $configData->getData()); + } + + /** + * testCreateConfigCacheRedis + */ + public function testCreateConfigWithIdPrefix() + { + $this->deploymentConfigMock->method('get')->willReturn(''); + + $explicitPrefix = 'XXX_'; + $expectedConfigData = [ + 'cache' => [ + 'frontend' => [ + 'default' => [ + 'id_prefix' => $explicitPrefix, + ] + ] + ] + ]; + + $configData = $this->configOptionsList->createConfig( + ['cache-id-prefix' => $explicitPrefix], + $this->deploymentConfigMock + ); + + $this->assertEquals($expectedConfigData, $configData->getData()); + } + /** * testValidateWithValidInput */ @@ -160,4 +214,14 @@ public function testValidateWithInvalidInput() $this->assertCount(1, $errors); $this->assertEquals("Invalid cache handler 'clay-tablet'", $errors[0]); } + + /** + * The default ID prefix, based on installation directory + * + * @return string + */ + private function expectedIdPrefix(): string + { + return substr(\md5(dirname(__DIR__, 8)), 0, 3) . '_'; + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php index 6f8e97cd5dd8d..d804266096f7b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php @@ -45,7 +45,7 @@ protected function setUp() public function testGetOptions() { $options = $this->configList->getOptions(); - $this->assertCount(6, $options); + $this->assertCount(7, $options); $this->assertArrayHasKey(0, $options); $this->assertInstanceOf(SelectConfigOption::class, $options[0]); @@ -70,6 +70,10 @@ public function testGetOptions() $this->assertArrayHasKey(5, $options); $this->assertInstanceOf(TextConfigOption::class, $options[5]); $this->assertEquals('page-cache-redis-password', $options[5]->getName()); + + $this->assertArrayHasKey(6, $options); + $this->assertInstanceOf(TextConfigOption::class, $options[6]); + $this->assertEquals('page-cache-id-prefix', $options[6]->getName()); } /** @@ -90,7 +94,8 @@ public function testCreateConfigWithRedis() 'database' => '', 'compress_data' => '', 'password' => '' - ] + ], + 'id_prefix' => $this->expectedIdPrefix(), ] ] ] @@ -117,7 +122,8 @@ public function testCreateConfigWithRedisConfiguration() 'database' => '6', 'compress_data' => '1', 'password' => '' - ] + ], + 'id_prefix' => $this->expectedIdPrefix(), ] ] ] @@ -136,6 +142,55 @@ public function testCreateConfigWithRedisConfiguration() $this->assertEquals($expectedConfigData, $configData->getData()); } + /** + * testCreateConfigWithRedis + */ + public function testCreateConfigWithFileCache() + { + $this->deploymentConfigMock->method('get')->willReturn(''); + + $expectedConfigData = [ + 'cache' => [ + 'frontend' => [ + 'page_cache' => [ + 'id_prefix' => $this->expectedIdPrefix(), + ] + ] + ] + ]; + + $configData = $this->configList->createConfig([], $this->deploymentConfigMock); + + $this->assertEquals($expectedConfigData, $configData->getData()); + } + + + /** + * testCreateConfigCacheRedis + */ + public function testCreateConfigWithIdPrefix() + { + $this->deploymentConfigMock->method('get')->willReturn(''); + + $explicitPrefix = 'XXX_'; + $expectedConfigData = [ + 'cache' => [ + 'frontend' => [ + 'page_cache' => [ + 'id_prefix' => $explicitPrefix, + ] + ] + ] + ]; + + $configData = $this->configList->createConfig( + ['page-cache-id-prefix' => $explicitPrefix], + $this->deploymentConfigMock + ); + + $this->assertEquals($expectedConfigData, $configData->getData()); + } + /** * testValidationWithValidData */ @@ -169,4 +224,14 @@ public function testValidationWithInvalidData() $this->assertCount(1, $errors); $this->assertEquals('Invalid cache handler \'foobar\'', $errors[0]); } + + /** + * The default ID prefix, based on installation directory + * + * @return string + */ + private function expectedIdPrefix(): string + { + return substr(\md5(dirname(__DIR__, 8)), 0, 3) . '_'; + } } From ff40c182383a75842e915db1c3aeb6ef8476c596 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Tue, 16 Oct 2018 12:47:30 +0300 Subject: [PATCH 0230/1158] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- .../StorefrontProductCartActionGroup.xml | 14 ++++ ...ProductWithZeroPriceToShoppingCartTest.xml | 77 +++++++++++++++++++ ...ctWithCustomOptionsWithLongValuesTitle.xml | 3 + .../Mftf/ActionGroup/CheckoutActionGroup.xml | 17 +++- .../Mftf/Section/AdminOrdersGridSection.xml | 2 +- 5 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml index f28ffbdc40acc..e36730a87b41a 100644 --- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml @@ -24,4 +24,18 @@ <waitForPageLoad time="30" stepKey="waitForPageLoad3"/> <waitForText userInput="{{quantity}}" selector="{{StorefrontMinicartSection.productCount}}" time="30" stepKey="assertProductCount"/> </actionGroup> + + <!-- Add Bundle Product to Cart from the category page --> + <actionGroup name="StorefrontAddBundleProductFromCategoryToCartActionGroup"> + <arguments> + <argument name="productName" type="string"/> + </arguments> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductTitleByName(productName)}}" stepKey="moveMouseOverProduct"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName(productName)}}" stepKey="openProductPage"/> + <waitForPageLoad time="30" stepKey="waitForBundleProductPageLoad"/> + <click selector="{{StorefrontBundledSection.addToCart}}" stepKey="clickCustomizeAndAddToCart"/> + <click selector="{{StorefrontBundledSection.addToCartConfigured}}" stepKey="clickAddBundleProductToCart"/> + <waitForElementVisible selector="{{StorefrontMinicartSection.productCount}}" stepKey="waitProductCount"/> + <see userInput="You added {{productName}} to your shopping cart." selector="{{StorefrontMessagesSection.success}}" stepKey="seeSuccessMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml new file mode 100644 index 0000000000000..71aaf76c42e84 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontAddBundleProductWithZeroPriceToShoppingCartTest"> + <annotations> + <features value="Bundle"/> + <stories value="Add Bundle product with zero price to shopping cart"/> + <title value="Add Bundle product with zero price to shopping cart"/> + <description value="Add Bundle product with zero price to shopping cart"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-95167"/> + <group value="bundle"/> + </annotations> + <before> + <!--Enable freeShipping--> + <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> + <!--Create category--> + <createData entity="SimpleSubCategory" stepKey="createSubCategory"/> + <!--Create simple with zero price product--> + <createData entity="ApiProductWithDescription" stepKey="apiSimple"> + <field key="price">0</field> + </createData> + <!--Create Bundle product--> + <createData entity="ApiBundleProductPriceViewRange" stepKey="apiBundleProduct"> + <requiredEntity createDataKey="createSubCategory"/> + </createData> + <!--Create Attribute--> + <createData entity="DropDownBundleOption" stepKey="bundleOption"> + <requiredEntity createDataKey="apiBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="createBundleLink"> + <requiredEntity createDataKey="apiBundleProduct"/> + <requiredEntity createDataKey="bundleOption"/> + <requiredEntity createDataKey="apiSimple"/> + </createData> + <magentoCLI command="indexer:reindex" stepKey="reindex"/> + </before> + <after> + <createData entity="FreeShippinMethodDefault" stepKey="disableFreeShipping"/> + <deleteData createDataKey="apiSimple" stepKey="deleteSimple"/> + <deleteData createDataKey="apiBundleProduct" stepKey="deleteBundleProduct"/> + <deleteData createDataKey="createSubCategory" stepKey="deleteCategory"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!--Open category page--> + <amOnPage url="{{StorefrontCategoryPage.url($$createSubCategory.custom_attributes[url_key]$$)}}" stepKey="amOnCategoryPage"/> + <!--Add bundle product to cart--> + <actionGroup ref="StorefrontAddBundleProductFromCategoryToCartActionGroup" stepKey="addBundleProductToCart"> + <argument name="productName" value="$$apiBundleProduct.name$$"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart"/> + + <!--Place order--> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShipping"> + <argument name="shippingMethod" value="Free Shipping"/> + </actionGroup> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="checkoutPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + + <!--Check subtotal in created order--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <scrollTo selector="{{AdminOrderTotalSection.subTotal}}" stepKey="scrollToOrderTotalSection"/> + <see selector="{{AdminOrderTotalSection.subTotal}}" userInput="$0.00" stepKey="checkSubtotal"/> + </test> +</tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml index a03636e52ee97..32d141d7e533e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml @@ -33,6 +33,8 @@ <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> + <actionGroup ref="logout" stepKey="logout"/> </after> <!-- Login Customer Storefront --> @@ -86,6 +88,7 @@ <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnOrdersPage"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearFilters"/> <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnSearch"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index 32d6ad8667029..d3dbf34c010c8 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -19,8 +19,10 @@ <!-- Guest checkout filling shipping section --> <actionGroup name="GuestCheckoutFillingShippingSectionActionGroup"> <arguments> - <argument name="customerVar"/> - <argument name="customerAddressVar"/> + <argument name="customerVar" defaultValue="CustomerEntityOne"/> + <argument name="customerAddressVar" defaultValue="CustomerAddressSimple"/> + <!--First available shipping method will be selected if value is not passed for shippingMethod--> + <argument name="shippingMethod" defaultValue="" type="string"/> </arguments> <fillField selector="{{CheckoutShippingSection.email}}" userInput="{{customerVar.email}}" stepKey="enterEmail"/> <fillField selector="{{CheckoutShippingSection.firstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> @@ -31,7 +33,7 @@ <fillField selector="{{CheckoutShippingSection.postcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> - <click selector="{{CheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <click selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('shippingMethod')}}" stepKey="selectShippingMethod"/> <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> @@ -154,6 +156,7 @@ <conditionalClick selector="{{CheckoutCartSummarySection.shippingHeading}}" dependentSelector="{{CheckoutCartSummarySection.country}}" visible="false" stepKey="openShippingDetails"/> <see selector="{{CheckoutCartSummarySection.countryParameterized('placeNumber')}}" userInput="{{country}}" stepKey="seeCountry"/> </actionGroup> + <actionGroup name="StorefrontSignOutActionGroup"> <click selector="{{StoreFrontSignOutSection.customerAccount}}" stepKey="clickCustomerButton"/> <click selector="{{StoreFrontSignOutSection.signOut}}" stepKey="clickToSignOut"/> @@ -161,4 +164,10 @@ <see userInput="You are signed out" stepKey="signOut"/> </actionGroup> -</actionGroups> \ No newline at end of file + <!--Click Place Order button--> + <actionGroup name="ClickPlaceOrderActionGroup"> + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <see selector="{{CheckoutSuccessMainSection.successTitle}}" userInput="Thank you for your purchase!" stepKey="waitForLoadSuccessPage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index 7ece18fb863b7..5e36a8f776628 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -22,7 +22,7 @@ <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> <element name="createNewOrder" type="button" selector=".page-actions-buttons button#add" timeout="30"/> - <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)" timeout="30"/> <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> <element name="viewBookmarkDropdown" type="button" selector="div.admin__data-grid-action-bookmarks button" timeout="30"/> From ecb1a7bf306e87eb54a08a7c5a19eac214838ce6 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 16 Oct 2018 13:10:15 +0200 Subject: [PATCH 0231/1158] Another attempt to execute tests --- .travis.yml | 22 ++++---- dev/tests/api-functional/phpunit.xml.dist | 56 ------------------- .../api-functional/phpunit_graphql.xml.dist | 2 +- dev/travis/before_install.sh | 2 +- dev/travis/before_script.sh | 29 ++++++++++ 5 files changed, 43 insertions(+), 68 deletions(-) delete mode 100644 dev/tests/api-functional/phpunit.xml.dist diff --git a/.travis.yml b/.travis.yml index c6077564b923d..930172a9ea6e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,14 @@ env: - NODE_JS_VERSION=8 - MAGENTO_HOST_NAME="magento2.travis" matrix: - - TEST_SUITE=unit - - TEST_SUITE=static - - TEST_SUITE=js GRUNT_COMMAND=spec - - TEST_SUITE=js GRUNT_COMMAND=static - - TEST_SUITE=integration INTEGRATION_INDEX=1 - - TEST_SUITE=integration INTEGRATION_INDEX=2 - - TEST_SUITE=integration INTEGRATION_INDEX=3 - - TEST_SUITE=functional +# - TEST_SUITE=unit +# - TEST_SUITE=static +# - TEST_SUITE=js GRUNT_COMMAND=spec +# - TEST_SUITE=js GRUNT_COMMAND=static +# - TEST_SUITE=integration INTEGRATION_INDEX=1 +# - TEST_SUITE=integration INTEGRATION_INDEX=2 +# - TEST_SUITE=integration INTEGRATION_INDEX=3 +# - TEST_SUITE=functional - TEST_SUITE=api-functional matrix: exclude: @@ -44,6 +44,8 @@ matrix: env: TEST_SUITE=js GRUNT_COMMAND=static - php: 7.1 env: TEST_SUITE=functional + - php: 7.1 + env: TEST_SUITE=api-functional cache: apt: true directories: @@ -62,6 +64,6 @@ script: # The scripts for grunt/phpunit type tests - if [ $TEST_SUITE == "functional" ]; then dev/tests/functional/vendor/phpunit/phpunit/phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - #- if [ $TEST_SUITE == "api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE/phpunit_graphql.xml.dist; fi + - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js"] && [ $TEST_SUITE != "api" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - if [ $TEST_SUITE == "js" ]; then grunt $GRUNT_COMMAND; fi + - if [ $TEST_SUITE == "api-functional" ]; then phpunit -c dev/tests/api-functional; fi diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist deleted file mode 100644 index a55531aba87e2..0000000000000 --- a/dev/tests/api-functional/phpunit.xml.dist +++ /dev/null @@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * PHPUnit configuration for GraphQL web API functional tests. - * - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.2/phpunit.xsd" - colors="true" - columns="max" - beStrictAboutTestsThatDoNotTestAnything="false" - bootstrap="./framework/bootstrap.php" -> - <!-- Test suites definition --> - <testsuites> - <testsuite name="Magento GraphQL web API functional tests"> - <directory suffix="Test.php">testsuite/Magento/GraphQl</directory> - </testsuite> - </testsuites> - - <!-- PHP INI settings and constants definition --> - <php> - <includePath>./testsuite</includePath> - <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> - <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/> - <!-- Webserver URL --> - <const name="TESTS_BASE_URL" value="http://magento2.travis"/> - <!-- Webserver API user --> - <const name="TESTS_WEBSERVICE_USER" value="admin"/> - <!-- Webserver API key --> - <const name="TESTS_WEBSERVICE_APIKEY" value="123123q"/> - <!-- Define if debugger should be started using XDEBUG_SESSION cookie --> - <const name="TESTS_XDEBUG_ENABLED" value="false"/> - <!-- Define XDEBUG_SESSION cookie value--> - <const name="TESTS_XDEBUG_SESSION" value="phpstorm" /> - - <ini name="date.timezone" value="America/Los_Angeles"/> - - <!-- Semicolon-separated 'glob' patterns, that match global XML configuration files --> - <const name="TESTS_GLOBAL_CONFIG_DIR" value="../../../app/etc"/> - <!-- Whether to cleanup the application before running tests or not --> - <const name="TESTS_CLEANUP" value="enabled"/> - <!--Defines if Magento should be installed before tests execution--> - <const name="TESTS_MAGENTO_INSTALLATION" value="disabled"/> - <!-- Magento mode for tests execution. Possible values are "default", "developer" and "production". --> - <const name="TESTS_MAGENTO_MODE" value="production"/> - </php> - - <!-- Test listeners --> - <listeners> - <listener class="Magento\TestFramework\Event\PhpUnit"/> - </listeners> -</phpunit> diff --git a/dev/tests/api-functional/phpunit_graphql.xml.dist b/dev/tests/api-functional/phpunit_graphql.xml.dist index 955a3a8953fa8..4a57c338ca3a2 100644 --- a/dev/tests/api-functional/phpunit_graphql.xml.dist +++ b/dev/tests/api-functional/phpunit_graphql.xml.dist @@ -27,7 +27,7 @@ <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/> <!-- Webserver URL --> - <const name="TESTS_BASE_URL" value="http://magento2.travis"/> + <const name="TESTS_BASE_URL" value="http://magento.url"/> <!-- Webserver API user --> <const name="TESTS_WEBSERVICE_USER" value="admin"/> <!-- Webserver API key --> diff --git a/dev/travis/before_install.sh b/dev/travis/before_install.sh index c9302f3b6672c..22d6c04dabda4 100755 --- a/dev/travis/before_install.sh +++ b/dev/travis/before_install.sh @@ -34,7 +34,7 @@ if [ $TEST_SUITE == "js" ]; then yarn global add grunt-cli fi -if [ $TEST_SUITE = "functional" ]; then +if [ $TEST_SUITE = "functional" or $TEST_SUITE = "api-functional" ]; then # Install apache sudo apt-get update sudo apt-get install apache2 libapache2-mod-fastcgi diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index 1dccc310c7a20..c27e65d3897c7 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -132,6 +132,35 @@ case $TEST_SUITE in php -f generate/moduleSequence.php php -f mtf troubleshooting:check-all + cd ../../.. + ;; + + api-functional) + echo "Installing Magento" + mysql -uroot -e 'CREATE DATABASE magento2;' + php bin/magento setup:install -q \ + --language="en_US" \ + --timezone="UTC" \ + --currency="USD" \ + --base-url="http://${MAGENTO_HOST_NAME}/" \ + --admin-firstname="John" \ + --admin-lastname="Doe" \ + --backend-frontname="backend" \ + --admin-email="admin@example.com" \ + --admin-user="admin" \ + --use-rewrites=1 \ + --admin-use-security-key=0 \ + --admin-password="123123q" + + echo "Enabling production mode" + php bin/magento deploy:mode:set production + + echo "Prepare api-functional tests for running" + cd dev/tests/api-functional + + cp ./phpunit_graphql.xml.dist ./phpunit.xml + sed -e "s?magento.url?${MAGENTO_HOST_NAME}?g" --in-place ./phpunit.xml + cd ../../.. ;; esac From 599cf87a2c7a7eabce65e482557dcfa8f649874c Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 16 Oct 2018 13:19:47 +0200 Subject: [PATCH 0232/1158] Condition fix for before_install script --- dev/travis/before_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/travis/before_install.sh b/dev/travis/before_install.sh index 22d6c04dabda4..44ba3fd8b74f1 100755 --- a/dev/travis/before_install.sh +++ b/dev/travis/before_install.sh @@ -34,7 +34,7 @@ if [ $TEST_SUITE == "js" ]; then yarn global add grunt-cli fi -if [ $TEST_SUITE = "functional" or $TEST_SUITE = "api-functional" ]; then +if [ $TEST_SUITE = "functional" ] || [ $TEST_SUITE = "api-functional" ]; then # Install apache sudo apt-get update sudo apt-get install apache2 libapache2-mod-fastcgi From 09e70057d810aa7004f7760b084d16b4833936b1 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 16 Oct 2018 13:27:48 +0200 Subject: [PATCH 0233/1158] Test api-functional tests alongside with other tests --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 930172a9ea6e0..f5a25bc63543d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,14 @@ env: - NODE_JS_VERSION=8 - MAGENTO_HOST_NAME="magento2.travis" matrix: -# - TEST_SUITE=unit -# - TEST_SUITE=static -# - TEST_SUITE=js GRUNT_COMMAND=spec -# - TEST_SUITE=js GRUNT_COMMAND=static -# - TEST_SUITE=integration INTEGRATION_INDEX=1 -# - TEST_SUITE=integration INTEGRATION_INDEX=2 -# - TEST_SUITE=integration INTEGRATION_INDEX=3 -# - TEST_SUITE=functional + - TEST_SUITE=unit + - TEST_SUITE=static + - TEST_SUITE=js GRUNT_COMMAND=spec + - TEST_SUITE=js GRUNT_COMMAND=static + - TEST_SUITE=integration INTEGRATION_INDEX=1 + - TEST_SUITE=integration INTEGRATION_INDEX=2 + - TEST_SUITE=integration INTEGRATION_INDEX=3 + - TEST_SUITE=functional - TEST_SUITE=api-functional matrix: exclude: From e3fc117bfa5158b51c875e76461539aba5b2b6a7 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 16 Oct 2018 15:33:43 +0300 Subject: [PATCH 0234/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- app/code/Magento/Catalog/etc/adminhtml/system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index 74661acb8f136..1b0fe4c85f617 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -206,7 +206,7 @@ <label>Images Upload Configuration</label> <field id="jpeg_quality" translate="label comment" type="text" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Quality</label> - <validate>validate-greater-than-zero validate-number required-entry digits-range-1-100</validate> + <validate>validate-greater-than-zero validate-digits validate-range required-entry digits-range-1-100</validate> <comment>Jpeg quality for resized images 1-100%.</comment> </field> </group> From 7691cd09aa475ca1440f3a5ea467d5da556d00c6 Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov <isentiabov@magento.com> Date: Tue, 16 Oct 2018 17:38:37 +0300 Subject: [PATCH 0235/1158] MAGETWO-94052: CAPTCHA does not appear in "Log in" popup window - Added captcha re-validation mechanism --- .../Model/Customer/Plugin/AjaxLogin.php | 26 +- app/code/Magento/Captcha/etc/di.xml | 2 +- .../view/frontend/web/js/model/captcha.js | 8 +- .../web/js/view/checkout/defaultCaptcha.js | 7 + .../web/js/view/checkout/loginCaptcha.js | 65 ++-- .../web/template/checkout/captcha.html | 6 +- .../Customer/Controller/Ajax/Login.php | 23 +- .../Test/Unit/Controller/Ajax/LoginTest.php | 334 ++++++++++-------- .../view/frontend/web/js/action/login.js | 4 +- 9 files changed, 260 insertions(+), 215 deletions(-) diff --git a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php index 91f3a785df36b..c67211be31659 100644 --- a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php +++ b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php @@ -3,13 +3,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Captcha\Model\Customer\Plugin; use Magento\Captcha\Helper\Data as CaptchaHelper; -use Magento\Framework\Session\SessionManagerInterface; +use Magento\Customer\Controller\Ajax\Login; +use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Session\SessionManagerInterface; +/** + * The plugin for ajax login controller. + */ class AjaxLogin { /** @@ -61,14 +67,14 @@ public function __construct( } /** - * @param \Magento\Customer\Controller\Ajax\Login $subject + * Validates captcha during request execution. + * + * @param Login $subject * @param \Closure $proceed * @return $this - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function aroundExecute( - \Magento\Customer\Controller\Ajax\Login $subject, + Login $subject, \Closure $proceed ) { $captchaFormIdField = 'captcha_form_id'; @@ -93,24 +99,28 @@ public function aroundExecute( foreach ($this->formIds as $formId) { if ($formId === $loginFormId) { $captchaModel = $this->helper->getCaptcha($formId); + if ($captchaModel->isRequired($username)) { - $captchaModel->logAttempt($username); if (!$captchaModel->isCorrect($captchaString)) { $this->sessionManager->setUsername($username); + $captchaModel->logAttempt($username); return $this->returnJsonError(__('Incorrect CAPTCHA')); } } + + $captchaModel->logAttempt($username); } } return $proceed(); } /** + * Gets Json response. * * @param \Magento\Framework\Phrase $phrase - * @return \Magento\Framework\Controller\Result\Json + * @return Json */ - private function returnJsonError(\Magento\Framework\Phrase $phrase): \Magento\Framework\Controller\Result\Json + private function returnJsonError(\Magento\Framework\Phrase $phrase): Json { $resultJson = $this->resultJsonFactory->create(); return $resultJson->setData(['errors' => true, 'message' => $phrase]); diff --git a/app/code/Magento/Captcha/etc/di.xml b/app/code/Magento/Captcha/etc/di.xml index 3a929f5e6cc00..83c4e8aa1e2c1 100644 --- a/app/code/Magento/Captcha/etc/di.xml +++ b/app/code/Magento/Captcha/etc/di.xml @@ -27,7 +27,7 @@ </arguments> </type> <type name="Magento\Customer\Controller\Ajax\Login"> - <plugin name="configurable_product" type="Magento\Captcha\Model\Customer\Plugin\AjaxLogin" sortOrder="50" /> + <plugin name="captcha_validation" type="Magento\Captcha\Model\Customer\Plugin\AjaxLogin" sortOrder="50" /> </type> <type name="Magento\Captcha\Model\Customer\Plugin\AjaxLogin"> <arguments> diff --git a/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js b/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js index 3a235df73a916..52968e507e6bf 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js @@ -17,7 +17,7 @@ define([ imageSource: ko.observable(captchaData.imageSrc), visibility: ko.observable(false), captchaValue: ko.observable(null), - isRequired: captchaData.isRequired, + isRequired: ko.observable(captchaData.isRequired), isCaseSensitive: captchaData.isCaseSensitive, imageHeight: captchaData.imageHeight, refreshUrl: captchaData.refreshUrl, @@ -41,7 +41,7 @@ define([ * @return {Boolean} */ getIsVisible: function () { - return this.visibility; + return this.visibility(); }, /** @@ -55,14 +55,14 @@ define([ * @return {Boolean} */ getIsRequired: function () { - return this.isRequired; + return this.isRequired(); }, /** * @param {Boolean} flag */ setIsRequired: function (flag) { - this.isRequired = flag; + this.isRequired(flag); }, /** diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js index f80b2ab163ffd..f78b848312702 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js @@ -89,6 +89,13 @@ define([ return this.currentCaptcha !== null ? this.currentCaptcha.getIsRequired() : false; }, + /** + * @param {Boolean} flag + */ + setIsRequired: function (flag) { + this.currentCaptcha.setIsRequired(flag); + }, + /** * @return {Boolean} */ diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js index 7709febea60a3..e017ca6fe274c 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js @@ -4,34 +4,43 @@ */ define([ - 'Magento_Captcha/js/view/checkout/defaultCaptcha', - 'Magento_Captcha/js/model/captchaList', - 'Magento_Customer/js/action/login' -], -function (defaultCaptcha, captchaList, loginAction) { - 'use strict'; - - return defaultCaptcha.extend({ - /** @inheritdoc */ - initialize: function () { - var self = this, - currentCaptcha; - - this._super(); - currentCaptcha = captchaList.getCaptchaByFormId(this.formId); - - if (currentCaptcha != null) { - currentCaptcha.setIsVisible(true); - this.setCurrentCaptcha(currentCaptcha); - - loginAction.registerLoginCallback(function (loginData) { - if (loginData['captcha_form_id'] && - loginData['captcha_form_id'] == self.formId //eslint-disable-line eqeqeq - ) { + 'Magento_Captcha/js/view/checkout/defaultCaptcha', + 'Magento_Captcha/js/model/captchaList', + 'Magento_Customer/js/action/login' + ], + function (defaultCaptcha, captchaList, loginAction) { + 'use strict'; + + return defaultCaptcha.extend({ + /** @inheritdoc */ + initialize: function () { + var self = this, + currentCaptcha; + + this._super(); + currentCaptcha = captchaList.getCaptchaByFormId(this.formId); + + if (currentCaptcha != null) { + currentCaptcha.setIsVisible(true); + this.setCurrentCaptcha(currentCaptcha); + + loginAction.registerLoginCallback(function (loginData, response) { + if (!response.errors) { + return; + } + + if (!loginData['captcha_form_id'] || loginData['captcha_form_id'] !== self.formId) { + return; + } + + // check if captcha should be required after login attempt + if (!self.isRequired() && response.captcha && self.isRequired() !== response.captcha) { + self.setIsRequired(response.captcha); + } + self.refresh(); - } - }); + }); + } } - } + }); }); -}); diff --git a/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html b/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html index 575b3ca6f732e..8923c81bf4bb3 100644 --- a/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html +++ b/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html @@ -4,12 +4,14 @@ * See COPYING.txt for license details. */ --> +<!-- ko if: (getIsVisible())--> +<input name="captcha_form_id" type="hidden" data-bind="value: formId, attr: {'data-scope': dataScope}" /> +<!-- /ko --> <!-- ko if: (isRequired() && getIsVisible())--> <div class="field captcha required" data-bind="blockLoader: getIsLoading()"> <label data-bind="attr: {for: 'captcha_' + formId}" class="label"><span data-bind="i18n: 'Please type the letters and numbers below'"></span></label> <div class="control captcha"> - <input name="captcha_string" type="text" class="input-text required-entry" data-bind="value: captchaValue(), attr: {id: 'captcha_' + formId, 'data-scope': dataScope}" autocomplete="off"/> - <input name="captcha_form_id" type="hidden" data-bind="value: formId, attr: {'data-scope': dataScope}" /> + <input name="captcha_string" type="text" class="input-text required-entry" data-bind="value: captchaValue(), attr: {'data-scope': dataScope}" autocomplete="off"/> <div class="nested"> <div class="field captcha no-label"> <div class="control captcha-image"> diff --git a/app/code/Magento/Customer/Controller/Ajax/Login.php b/app/code/Magento/Customer/Controller/Ajax/Login.php index 7d1e86c949792..6d0f8c036b290 100644 --- a/app/code/Magento/Customer/Controller/Ajax/Login.php +++ b/app/code/Magento/Customer/Controller/Ajax/Login.php @@ -107,7 +107,6 @@ public function __construct( /** * Get account redirect. - * For release backward compatibility. * * @deprecated 100.0.10 * @return AccountRedirect @@ -133,6 +132,8 @@ public function setAccountRedirect($value) } /** + * Initializes config dependency. + * * @deprecated 100.0.10 * @return ScopeConfigInterface */ @@ -145,6 +146,8 @@ protected function getScopeConfig() } /** + * Sets config dependency. + * * @deprecated 100.0.10 * @param ScopeConfigInterface $value * @return void @@ -199,25 +202,17 @@ public function execute() $response['redirectUrl'] = $this->_redirect->success($redirectRoute); $this->getAccountRedirect()->clearRedirectCookie(); } - } catch (EmailNotConfirmedException $e) { - $response = [ - 'errors' => true, - 'message' => $e->getMessage() - ]; - } catch (InvalidEmailOrPasswordException $e) { - $response = [ - 'errors' => true, - 'message' => $e->getMessage() - ]; - } catch (LocalizedException $e) { + } catch (LocalizedException | InvalidEmailOrPasswordException | EmailNotConfirmedException $e) { $response = [ 'errors' => true, - 'message' => $e->getMessage() + 'message' => $e->getMessage(), + 'captcha' => $this->customerSession->getData('user_login_show_captcha') ]; } catch (\Exception $e) { $response = [ 'errors' => true, - 'message' => __('Invalid login or password.') + 'message' => __('Invalid login or password.'), + 'captcha' => $this->customerSession->getData('user_login_show_captcha') ]; } /** @var \Magento\Framework\Controller\Result\Json $resultJson */ 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 aaaa799a5e26d..628727b202ba7 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php @@ -3,13 +3,32 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -/** - * Test customer ajax login controller - */ namespace Magento\Customer\Test\Unit\Controller\Ajax; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Controller\Ajax\Login; +use Magento\Customer\Model\Account\Redirect; +use Magento\Customer\Model\AccountManagement; +use Magento\Customer\Model\Session; +use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\Request\Http; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\App\ResponseInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Controller\Result\Raw; +use Magento\Framework\Controller\Result\RawFactory; use Magento\Framework\Exception\InvalidEmailOrPasswordException; +use Magento\Framework\Json\Helper\Data; +use Magento\Framework\ObjectManager\ObjectManager as FakeObjectManager; +use Magento\Framework\Stdlib\Cookie\CookieMetadata; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; +use Magento\Framework\Stdlib\CookieManagerInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -17,223 +36,190 @@ class LoginTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Customer\Controller\Ajax\Login + * @var Login */ - protected $object; + private $controller; /** - * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject + * @var Http|MockObject */ - protected $request; + private $request; /** - * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ResponseInterface|MockObject */ - protected $response; + private $response; /** - * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject + * @var Session|MockObject */ - protected $customerSession; + private $customerSession; /** - * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var FakeObjectManager|MockObject */ - protected $objectManager; + private $objectManager; /** - * @var \Magento\Customer\Api\AccountManagementInterface|\PHPUnit_Framework_MockObject_MockObject + * @var AccountManagement|MockObject */ - protected $customerAccountManagementMock; + private $accountManagement; /** - * @var \Magento\Framework\Json\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + * @var Data|MockObject */ - protected $jsonHelperMock; + private $jsonHelper; /** - * @var \Magento\Framework\Controller\Result\Json|\PHPUnit_Framework_MockObject_MockObject + * @var Json|MockObject */ - protected $resultJson; + private $resultJson; /** - * @var \Magento\Framework\Controller\Result\JsonFactory| \PHPUnit_Framework_MockObject_MockObject + * @var JsonFactory|MockObject */ - protected $resultJsonFactory; + private $resultJsonFactory; /** - * @var \Magento\Framework\Controller\Result\Raw| \PHPUnit_Framework_MockObject_MockObject + * @var Raw|MockObject */ - protected $resultRaw; + private $resultRaw; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var RedirectInterface|MockObject */ - protected $redirectMock; + private $redirect; /** - * @var \Magento\Framework\Stdlib\CookieManagerInterface| \PHPUnit_Framework_MockObject_MockObject + * @var CookieManagerInterface|MockObject */ private $cookieManager; /** - * @var \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory| \PHPUnit_Framework_MockObject_MockObject + * @var CookieMetadataFactory|MockObject */ private $cookieMetadataFactory; /** - * @var \Magento\Framework\Stdlib\Cookie\CookieMetadata| \PHPUnit_Framework_MockObject_MockObject + * @inheritdoc */ - private $cookieMetadata; - - protected function setUp() + protected function setUp(): void { - $this->request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) - ->disableOriginalConstructor()->getMock(); + $this->request = $this->getMockBuilder(Http::class) + ->disableOriginalConstructor() + ->getMock(); $this->response = $this->createPartialMock( - \Magento\Framework\App\ResponseInterface::class, + ResponseInterface::class, ['setRedirect', 'sendResponse', 'representJson', 'setHttpResponseCode'] ); $this->customerSession = $this->createPartialMock( - \Magento\Customer\Model\Session::class, + Session::class, [ 'isLoggedIn', 'getLastCustomerId', 'getBeforeAuthUrl', 'setBeforeAuthUrl', 'setCustomerDataAsLoggedIn', - 'regenerateId' + 'regenerateId', + 'getData' ] ); - $this->objectManager = $this->createPartialMock(\Magento\Framework\ObjectManager\ObjectManager::class, ['get']); - $this->customerAccountManagementMock = - $this->createPartialMock(\Magento\Customer\Model\AccountManagement::class, ['authenticate']); + $this->objectManager = $this->createPartialMock(FakeObjectManager::class, ['get']); + $this->accountManagement = $this->createPartialMock(AccountManagement::class, ['authenticate']); - $this->jsonHelperMock = $this->createPartialMock(\Magento\Framework\Json\Helper\Data::class, ['jsonDecode']); + $this->jsonHelper = $this->createPartialMock(Data::class, ['jsonDecode']); - $this->resultJson = $this->getMockBuilder(\Magento\Framework\Controller\Result\Json::class) + $this->resultJson = $this->getMockBuilder(Json::class) ->disableOriginalConstructor() ->getMock(); - $this->resultJsonFactory = $this->getMockBuilder(\Magento\Framework\Controller\Result\JsonFactory::class) + $this->resultJsonFactory = $this->getMockBuilder(JsonFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $this->cookieManager = $this->getMockBuilder(\Magento\Framework\Stdlib\CookieManagerInterface::class) + $this->cookieManager = $this->getMockBuilder(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) + $this->cookieMetadataFactory = $this->getMockBuilder(CookieMetadataFactory::class) ->disableOriginalConstructor() ->getMock(); - $this->resultRaw = $this->getMockBuilder(\Magento\Framework\Controller\Result\Raw::class) + $this->resultRaw = $this->getMockBuilder(Raw::class) ->disableOriginalConstructor() ->getMock(); - $resultRawFactory = $this->getMockBuilder(\Magento\Framework\Controller\Result\RawFactory::class) + $resultRawFactory = $this->getMockBuilder(RawFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $resultRawFactory->expects($this->atLeastOnce()) - ->method('create') + $resultRawFactory->method('create') ->willReturn($this->resultRaw); - $contextMock = $this->createMock(\Magento\Framework\App\Action\Context::class); - $this->redirectMock = $this->createMock(\Magento\Framework\App\Response\RedirectInterface::class); - $contextMock->expects($this->atLeastOnce())->method('getRedirect')->willReturn($this->redirectMock); - $contextMock->expects($this->atLeastOnce())->method('getRequest')->willReturn($this->request); - - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->object = $objectManager->getObject( - \Magento\Customer\Controller\Ajax\Login::class, + /** @var Context|MockObject $context */ + $context = $this->createMock(Context::class); + $this->redirect = $this->createMock(RedirectInterface::class); + $context->method('getRedirect') + ->willReturn($this->redirect); + $context->method('getRequest') + ->willReturn($this->request); + + $objectManager = new ObjectManager($this); + $this->controller = $objectManager->getObject( + Login::class, [ - 'context' => $contextMock, + 'context' => $context, 'customerSession' => $this->customerSession, - 'helper' => $this->jsonHelperMock, + 'helper' => $this->jsonHelper, 'response' => $this->response, 'resultRawFactory' => $resultRawFactory, 'resultJsonFactory' => $this->resultJsonFactory, 'objectManager' => $this->objectManager, - 'customerAccountManagement' => $this->customerAccountManagementMock, + 'customerAccountManagement' => $this->accountManagement, 'cookieManager' => $this->cookieManager, 'cookieMetadataFactory' => $this->cookieMetadataFactory ] ); } - public function testLogin() + /** + * Checks successful login. + */ + public function testLogin(): void { $jsonRequest = '{"username":"customer@example.com", "password":"password"}'; $loginSuccessResponse = '{"errors": false, "message":"Login successful."}'; + $this->withRequest($jsonRequest); - $this->request - ->expects($this->any()) - ->method('getContent') - ->willReturn($jsonRequest); - - $this->request - ->expects($this->any()) - ->method('getMethod') - ->willReturn('POST'); - - $this->request - ->expects($this->any()) - ->method('isXmlHttpRequest') - ->willReturn(true); - - $this->resultJsonFactory->expects($this->atLeastOnce()) - ->method('create') + $this->resultJsonFactory->method('create') ->willReturn($this->resultJson); - $this->jsonHelperMock - ->expects($this->any()) - ->method('jsonDecode') + $this->jsonHelper->method('jsonDecode') ->with($jsonRequest) ->willReturn(['username' => 'customer@example.com', 'password' => 'password']); - $customerMock = $this->getMockForAbstractClass(\Magento\Customer\Api\Data\CustomerInterface::class); - $this->customerAccountManagementMock - ->expects($this->any()) - ->method('authenticate') + /** @var CustomerInterface|MockObject $customer */ + $customer = $this->getMockForAbstractClass(CustomerInterface::class); + $this->accountManagement->method('authenticate') ->with('customer@example.com', 'password') - ->willReturn($customerMock); + ->willReturn($customer); - $this->customerSession->expects($this->once()) - ->method('setCustomerDataAsLoggedIn') - ->with($customerMock); + $this->customerSession->method('setCustomerDataAsLoggedIn') + ->with($customer); + $this->customerSession->method('regenerateId'); - $this->customerSession->expects($this->once())->method('regenerateId'); + /** @var Redirect|MockObject $redirect */ + $redirect = $this->createMock(Redirect::class); + $this->controller->setAccountRedirect($redirect); + $redirect->method('getRedirectCookie') + ->willReturn('some_url1'); - $redirectMock = $this->createMock(\Magento\Customer\Model\Account\Redirect::class); - $this->object->setAccountRedirect($redirectMock); - $redirectMock->expects($this->once())->method('getRedirectCookie')->willReturn('some_url1'); + $this->withCookieManager(); - $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(); + $this->withScopeConfig(); - $scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); - $this->object->setScopeConfig($scopeConfigMock); - $scopeConfigMock->expects($this->once())->method('getValue') - ->with('customer/startup/redirect_dashboard') - ->willReturn(0); - - $this->redirectMock->expects($this->once())->method('success')->willReturn('some_url2'); - $this->resultRaw->expects($this->never())->method('setHttpResponseCode'); + $this->redirect->method('success') + ->willReturn('some_url2'); + $this->resultRaw->expects(self::never()) + ->method('setHttpResponseCode'); $result = [ 'errors' => false, @@ -241,67 +227,103 @@ public function testLogin() 'redirectUrl' => 'some_url2', ]; - $this->resultJson - ->expects($this->once()) - ->method('setData') + $this->resultJson->method('setData') ->with($result) ->willReturn($loginSuccessResponse); - $this->assertEquals($loginSuccessResponse, $this->object->execute()); + self::assertEquals($loginSuccessResponse, $this->controller->execute()); } - public function testLoginFailure() + /** + * Checks unsuccessful login. + */ + public function testLoginFailure(): void { $jsonRequest = '{"username":"invalid@example.com", "password":"invalid"}'; $loginFailureResponse = '{"message":"Invalid login or password."}'; + $this->withRequest($jsonRequest); - $this->request - ->expects($this->any()) - ->method('getContent') - ->willReturn($jsonRequest); - - $this->request - ->expects($this->any()) - ->method('getMethod') - ->willReturn('POST'); - - $this->request - ->expects($this->any()) - ->method('isXmlHttpRequest') - ->willReturn(true); - - $this->resultJsonFactory->expects($this->once()) - ->method('create') + $this->resultJsonFactory->method('create') ->willReturn($this->resultJson); - $this->jsonHelperMock - ->expects($this->any()) - ->method('jsonDecode') + $this->jsonHelper->method('jsonDecode') ->with($jsonRequest) ->willReturn(['username' => 'invalid@example.com', 'password' => 'invalid']); - $customerMock = $this->getMockForAbstractClass(\Magento\Customer\Api\Data\CustomerInterface::class); - $this->customerAccountManagementMock - ->expects($this->any()) - ->method('authenticate') + /** @var CustomerInterface|MockObject $customer */ + $customer = $this->getMockForAbstractClass(CustomerInterface::class); + $this->accountManagement->method('authenticate') ->with('invalid@example.com', 'invalid') ->willThrowException(new InvalidEmailOrPasswordException(__('Invalid login or password.'))); - $this->customerSession->expects($this->never()) + $this->customerSession->expects(self::never()) ->method('setCustomerDataAsLoggedIn') - ->with($customerMock); - - $this->customerSession->expects($this->never())->method('regenerateId'); + ->with($customer); + $this->customerSession->expects(self::never()) + ->method('regenerateId'); + $this->customerSession->method('getData') + ->with('user_login_show_captcha') + ->willReturn(false); $result = [ 'errors' => true, - 'message' => __('Invalid login or password.') + 'message' => __('Invalid login or password.'), + 'captcha' => false ]; - $this->resultJson - ->expects($this->once()) - ->method('setData') + $this->resultJson->method('setData') ->with($result) ->willReturn($loginFailureResponse); - $this->assertEquals($loginFailureResponse, $this->object->execute()); + self::assertEquals($loginFailureResponse, $this->controller->execute()); + } + + /** + * Emulates request behavior. + * + * @param string $jsonRequest + */ + private function withRequest(string $jsonRequest): void + { + $this->request->method('getContent') + ->willReturn($jsonRequest); + + $this->request->method('getMethod') + ->willReturn('POST'); + + $this->request->method('isXmlHttpRequest') + ->willReturn(true); + } + + /** + * Emulates cookie manager behavior. + */ + private function withCookieManager(): void + { + $this->cookieManager->method('getCookie') + ->with('mage-cache-sessid') + ->willReturn(true); + $cookieMetadata = $this->getMockBuilder(CookieMetadata::class) + ->disableOriginalConstructor() + ->getMock(); + $this->cookieMetadataFactory->method('createCookieMetadata') + ->willReturn($cookieMetadata); + $cookieMetadata->method('setPath') + ->with('/') + ->willReturnSelf(); + $this->cookieManager->method('deleteCookie') + ->with('mage-cache-sessid', $cookieMetadata) + ->willReturnSelf(); + } + + /** + * Emulates config behavior. + */ + private function withScopeConfig(): void + { + /** @var ScopeConfigInterface|MockObject $scopeConfig */ + $scopeConfig = $this->createMock(ScopeConfigInterface::class); + $this->controller->setScopeConfig($scopeConfig); + $scopeConfig->method('getValue') + ->with('customer/startup/redirect_dashboard') + ->willReturn(0); } } diff --git a/app/code/Magento/Customer/view/frontend/web/js/action/login.js b/app/code/Magento/Customer/view/frontend/web/js/action/login.js index d75b8f70c5346..0015e2732e383 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/action/login.js +++ b/app/code/Magento/Customer/view/frontend/web/js/action/login.js @@ -31,11 +31,11 @@ define([ if (response.errors) { messageContainer.addErrorMessage(response); callbacks.forEach(function (callback) { - callback(loginData); + callback(loginData, response); }); } else { callbacks.forEach(function (callback) { - callback(loginData); + callback(loginData, response); }); customerData.invalidate(['customer']); From d5594fc7dd8e93ded92576925f903bffd3a686ad Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Tue, 16 Oct 2018 23:55:26 -0500 Subject: [PATCH 0236/1158] MAGETWO-95645: Custom file attribute works incorrect --- .../Magento/Eav/Model/Attribute/Data/File.php | 17 ++++++++++++--- .../jasmine/tests/lib/mage/validation.test.js | 20 ++++++++++++++++++ .../Framework/Data/Form/Element/Text.php | 1 + lib/web/mage/validation.js | 21 +++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Eav/Model/Attribute/Data/File.php b/app/code/Magento/Eav/Model/Attribute/Data/File.php index 5e2e2716e13d2..3d73ffa378232 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/File.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/File.php @@ -147,7 +147,7 @@ protected function _validateByRules($value) return $this->_fileValidator->getMessages(); } - if (!is_uploaded_file($value['tmp_name'])) { + if (!empty($value['tmp_name']) && !is_uploaded_file($value['tmp_name'])) { return [__('"%1" is not a valid file.', $label)]; } @@ -174,12 +174,21 @@ public function validateValue($value) if ($this->getIsAjaxRequest()) { return true; } + $fileData = $value; + + if (is_string($value) && !empty($value)) { + $dir = $this->_directory->getAbsolutePath($this->getAttribute()->getEntityType()->getEntityTypeCode()); + $fileData = [ + 'size' => filesize($dir . $value), + 'name' => $value + ]; + } $errors = []; $attribute = $this->getAttribute(); $toDelete = !empty($value['delete']) ? true : false; - $toUpload = !empty($value['tmp_name']) ? true : false; + $toUpload = !empty($value['tmp_name']) || is_string($value) && !empty($value) ? true : false; if (!$toUpload && !$toDelete && $this->getEntity()->getData($attribute->getAttributeCode())) { return true; @@ -195,11 +204,13 @@ public function validateValue($value) } if ($toUpload) { - $errors = array_merge($errors, $this->_validateByRules($value)); + $errors = array_merge($errors, $this->_validateByRules($fileData)); } if (count($errors) == 0) { return true; + } elseif (is_string($value) && !empty($value)) { + $this->_directory->delete($dir . $value); } return $errors; diff --git a/dev/tests/js/jasmine/tests/lib/mage/validation.test.js b/dev/tests/js/jasmine/tests/lib/mage/validation.test.js index 1e1203d22a1e3..ca9ec877013f8 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/validation.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/validation.test.js @@ -1142,4 +1142,24 @@ define([ )).toEqual(true); }); }); + + describe('Testing validate-forbidden-extensions', function () { + it('validate-forbidden-extensions', function () { + var el1 = $('<input type="text" value="" ' + + 'class="validate-extensions" data-validation-params="php,phtml">').get(0); + + expect($.validator.methods['validate-forbidden-extensions'] + .call($.validator.prototype, 'php', el1, null)).toEqual(false); + expect($.validator.methods['validate-forbidden-extensions'] + .call($.validator.prototype, 'php,phtml', el1, null)).toEqual(false); + expect($.validator.methods['validate-forbidden-extensions'] + .call($.validator.prototype, 'html', el1, null)).toEqual(true); + expect($.validator.methods['validate-forbidden-extensions'] + .call($.validator.prototype, 'html,png', el1, null)).toEqual(true); + expect($.validator.methods['validate-forbidden-extensions'] + .call($.validator.prototype, 'php,html', el1, null)).toEqual(false); + expect($.validator.methods['validate-forbidden-extensions'] + .call($.validator.prototype, 'html,php', el1, null)).toEqual(false); + }); + }); }); diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Text.php b/lib/internal/Magento/Framework/Data/Form/Element/Text.php index eb157c7279a71..b7b084310ed14 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Text.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Text.php @@ -65,6 +65,7 @@ public function getHtmlAttributes() 'placeholder', 'data-form-part', 'data-role', + 'data-validation-params', 'data-action' ]; } diff --git a/lib/web/mage/validation.js b/lib/web/mage/validation.js index 86dd5a3b03681..e79cc3cd24d83 100644 --- a/lib/web/mage/validation.js +++ b/lib/web/mage/validation.js @@ -881,6 +881,27 @@ }, $.mage.__('Please enter a valid number in this field.') ], + 'validate-forbidden-extensions': [ + function (v, elem) { + var forbiddenExtensions = $(elem).attr('data-validation-params'), + forbiddenExtensionsArray = forbiddenExtensions.split(','), + extensionsArray = v.split(','), + result = true; + + this.validateExtensionsMessage = $.mage.__('Forbidden extensions has been used. Avoid usage of ') + + forbiddenExtensions; + + $.each(extensionsArray, function (key, extension) { + if (forbiddenExtensionsArray.indexOf(extension) !== -1) { + result = false; + } + }); + + return result; + }, function () { + return this.validateExtensionsMessage; + } + ], 'validate-digits-range': [ function (v, elm, param) { var numValue, dataAttrRange, classNameRange, result, range, m, classes, ii; From f2960de5d130bad5ae78023fc5f20f9187f78fc0 Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Mon, 15 Oct 2018 15:55:24 -0500 Subject: [PATCH 0237/1158] MAGETWO-95363: Update Magento\Ui\Controller\Adminhtml\Index\Render\Handle controller --- .../Adminhtml/Index/Render/Handle.php | 41 ++++++++++++++++--- .../Adminhtml/Index/Render/HandleTest.php | 8 +++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php index 3b2a81fdac729..6ea14448c4aef 100644 --- a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php +++ b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php @@ -10,12 +10,37 @@ use Magento\Ui\Component\Control\ActionPool; use Magento\Ui\Component\Wrapper\UiComponent; use Magento\Ui\Controller\Adminhtml\AbstractAction; +use Magento\Backend\App\Action\Context; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Framework\View\Element\UiComponent\ContextFactory; +use Magento\Framework\App\ObjectManager; /** * Class Handle + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Handle extends AbstractAction implements HttpGetActionInterface { + /** + * @var ContextFactory + */ + private $contextFactory; + + /** + * @param Context $context + * @param UiComponentFactory $factory + * @param ContextFactory|null $contextFactory + */ + public function __construct( + Context $context, + UiComponentFactory $factory, + ContextFactory $contextFactory = null + ) { + parent::__construct($context, $factory); + $this->contextFactory = $contextFactory + ?: ObjectManager::getInstance()->get(ContextFactory::class); + } + /** * Render UI component by namespace in handle context * @@ -27,17 +52,23 @@ public function execute() $handle = $this->_request->getParam('handle'); $namespace = $this->_request->getParam('namespace'); $buttons = $this->_request->getParam('buttons', false); + $this->_view->loadLayout(['default', $handle], true, true, false); + $layout = $this->_view->getLayout(); + $context = $this->contextFactory->create( + [ + 'namespace' => $namespace, + 'pageLayout' => $layout + ] + ); - $component = $this->factory->create($namespace); + $component = $this->factory->create($namespace, null, ['context' => $context]); if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) { - $this->_view->loadLayout(['default', $handle], true, true, false); - - $uiComponent = $this->_view->getLayout()->getBlock($namespace); + $uiComponent = $layout->getBlock($namespace); $response = $uiComponent instanceof UiComponent ? $uiComponent->toHtml() : ''; } if ($buttons) { - $actionsToolbar = $this->_view->getLayout()->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR); + $actionsToolbar = $layout->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR); $response .= $actionsToolbar instanceof Template ? $actionsToolbar->toHtml() : ''; } diff --git a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php index e7752678f0c86..d31537458f213 100644 --- a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php +++ b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php @@ -8,6 +8,9 @@ use Magento\Ui\Controller\Adminhtml\Index\Render\Handle; use Magento\Framework\View\Element\UiComponent\ContextInterface; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class HandleTest extends \PHPUnit\Framework\TestCase { /** @@ -102,7 +105,8 @@ public function setUp() $this->dataProviderMock->expects($this->once()) ->method('getConfigData') ->willReturn([]); - $this->controller = new Handle($this->contextMock, $this->uiFactoryMock); + $contextMock = $this->createMock(\Magento\Framework\View\Element\UiComponent\ContextFactory::class); + $this->controller = new Handle($this->contextMock, $this->uiFactoryMock, $contextMock); } public function testExecuteNoButtons() @@ -132,7 +136,7 @@ public function testExecute() ->with(['default', $result], true, true, false); $layoutMock = $this->createMock(\Magento\Framework\View\LayoutInterface::class); - $this->viewMock->expects($this->exactly(2))->method('getLayout')->willReturn($layoutMock); + $this->viewMock->expects($this->once())->method('getLayout')->willReturn($layoutMock); $layoutMock->expects($this->exactly(2))->method('getBlock'); From 2f76498e2fe0d67af352c6a319e08e84dc3f2019 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Wed, 17 Oct 2018 15:50:21 -0500 Subject: [PATCH 0238/1158] MQE-1187: Fix MFTF skipped tests - Fixed RestrictedAdminCreateCMSBlockTest - Refactored WYSIWYG enable to a CLI action, way faster and more robust - Moved AdminRole/AdminUser action groups to User module, as it belongs there regardless. --- .../ActionGroup/ConfigWYSIWYGActionGroup.xml | 19 ++----------------- .../Mftf/ActionGroup/AdminRoleActionGroup.xml | 7 +++++-- .../Mftf/ActionGroup/AdminUserActionGroup.xml | 3 +-- 3 files changed, 8 insertions(+), 21 deletions(-) rename app/code/Magento/{Braintree => User}/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml (83%) rename app/code/Magento/{Braintree => User}/Test/Mftf/ActionGroup/AdminUserActionGroup.xml (98%) diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml index 3c043b28801e2..48eeb79a15ed0 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml @@ -9,25 +9,10 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="EnabledWYSIWYG"> - <amOnPage url="{{ConfigurationStoresPage.url}}" stepKey="navigateToConfigurationPage" /> - <waitForPageLoad stepKey="wait1"/> - <conditionalClick stepKey="expandWYSIWYGOptions" selector="{{ContentManagementSection.WYSIWYGOptions}}" dependentSelector="{{ContentManagementSection.CheckIfTabExpand}}" visible="true" /> - <waitForElementVisible selector="{{ContentManagementSection.EnableWYSIWYG}}" stepKey="waitForEnableWYSIWYGDropdown1" /> - <waitForElementVisible selector="{{ContentManagementSection.EnableSystemValue}}" stepKey="waitForUseSystemValueVisible"/> - <uncheckOption selector="{{ContentManagementSection.EnableSystemValue}}" stepKey="uncheckUseSystemValue"/> - <selectOption selector="{{ContentManagementSection.EnableWYSIWYG}}" userInput="Enabled by Default" stepKey="selectOption1"/> - <click selector="{{ContentManagementSection.WYSIWYGOptions}}" stepKey="collapseWYSIWYGOptions" /> - <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig" /> + <magentoCLI stepKey="enableWYSIWYG" command="config:set cms/wysiwyg/enabled enabled"/> </actionGroup> <actionGroup name="DisabledWYSIWYG"> - <amOnPage url="{{ConfigurationStoresPage.url}}" stepKey="navigateToConfigurationPage" /> - <waitForPageLoad stepKey="wait3"/> - <conditionalClick stepKey="expandWYSIWYGOptions" selector="{{ContentManagementSection.WYSIWYGOptions}}" dependentSelector="{{ContentManagementSection.CheckIfTabExpand}}" visible="true" /> - <waitForElementVisible selector="{{ContentManagementSection.EnableWYSIWYG}}" stepKey="waitForEnableWYSIWYGDropdown2" time="30"/> - <uncheckOption selector="{{ContentManagementSection.EnableSystemValue}}" stepKey="uncheckUseSystemValue"/> - <selectOption selector="{{ContentManagementSection.EnableWYSIWYG}}" userInput="Disabled Completely" stepKey="selectOption2"/> - <click selector="{{ContentManagementSection.WYSIWYGOptions}}" stepKey="collapseWYSIWYGOptions" /> - <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig" /> + <magentoCLI stepKey="disableWYSIWYG" command="config:set cms/wysiwyg/enabled disabled"/> </actionGroup> <actionGroup name="UseStaticURLForMediaContentInWYSIWYG"> <arguments> diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml similarity index 83% rename from app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml rename to app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml index e86d5403e11eb..b1ac0820923d9 100644 --- a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml @@ -7,7 +7,6 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="GoToUserRoles"> <click selector="#menu-magento-backend-system" stepKey="clickOnSystemIcon"/> <waitForPageLoad stepKey="waitForSystemsPageToOpen"/> @@ -28,7 +27,11 @@ <fillField stepKey="setPassword" selector="{{AdminCreateRoleSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> <click selector="{{AdminCreateRoleSection.roleResources}}" stepKey="clickToOpenRoleResources"/> <waitForPageLoad stepKey="waitForRoleResourcePage" time="5"/> - <click stepKey="checkSales" selector="//a[text()='Sales']"/> + <click selector="{{AdminCreateRoleSection.roleResource}}" stepKey="clickToExpandResourceAccess"/> + <click selector="{{AdminCreateRoleSection.resourceValue(scope)}}" stepKey="clickToSelectResourceAccess"/> + <click selector="{{AdminCreateRoleSection.roleScope}}" stepKey="clickToExpandScopeAccess"/> + <click selector="{{AdminCreateRoleSection.scopeValue(resource)}}" stepKey="clickToSelectScopeAccess"/> + <click selector="{{AdminCreateRoleSection.website(websites)}}" stepKey="clickToSelectWebsite"/> <click selector="{{AdminCreateRoleSection.save}}" stepKey="clickToSaveRole"/> <waitForPageLoad stepKey="waitForPageLoad" time="10"/> <see userInput="You saved the role." stepKey="seeSuccessMessage" /> diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminUserActionGroup.xml similarity index 98% rename from app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml rename to app/code/Magento/User/Test/Mftf/ActionGroup/AdminUserActionGroup.xml index 23c322083773c..3e776df9fb97f 100644 --- a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminUserActionGroup.xml @@ -42,8 +42,8 @@ <!--Delete User--> <actionGroup name="AdminDeleteUserActionGroup"> - <click stepKey="clickOnUser" selector="{{AdminDeleteUserSection.theUser}}"/> + <waitForPageLoad stepKey="waitForUserPageToLoad"/> <fillField stepKey="TypeCurrentPassword" selector="{{AdminDeleteUserSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> <scrollToTopOfPage stepKey="scrollToTop"/> <click stepKey="clickToDeleteUser" selector="{{AdminDeleteUserSection.delete}}"/> @@ -52,5 +52,4 @@ <waitForPageLoad stepKey="waitForPageLoad" time="10"/> <see userInput="You deleted the user." stepKey="seeSuccessMessage" /> </actionGroup> - </actionGroups> From ad91d28d2602bb126834deb4350cdcff2186355b Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Wed, 17 Oct 2018 16:55:52 -0500 Subject: [PATCH 0239/1158] MAGETWO-95642: Import error --- .../Controller/Adminhtml/Import/Validate.php | 18 +++++--- .../Magento/ImportExport/Model/Import.php | 42 +++++++++++++++--- .../ImportExport/Model/Import/Source/Zip.php | 11 ++--- .../Adminhtml/Import/ValidateTest.php | 17 ++++++- .../Import/_files/catalog_product.zip | Bin 0 -> 955 bytes .../Magento/Framework/Archive/Zip.php | 16 ++++--- 6 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/catalog_product.zip diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php index 204e9b11085ed..a0992e28bb2cd 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php @@ -13,6 +13,10 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\ImportExport\Model\Import\Adapter as ImportAdapter; +/** + * Import validate controller action. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class Validate extends ImportResultController implements HttpPostActionInterface { /** @@ -24,6 +28,7 @@ class Validate extends ImportResultController implements HttpPostActionInterface * Validate uploaded files action * * @return \Magento\Framework\Controller\ResultInterface + * @SuppressWarnings(PHPMD.Superglobals) */ public function execute() { @@ -42,12 +47,7 @@ public function execute() /** @var $import \Magento\ImportExport\Model\Import */ $import = $this->getImport()->setData($data); try { - $source = ImportAdapter::findAdapterFor( - $import->uploadSource(), - $this->_objectManager->create(\Magento\Framework\Filesystem::class) - ->getDirectoryWrite(DirectoryList::ROOT), - $data[$import::FIELD_FIELD_SEPARATOR] - ); + $source = $import->uploadFileAndGetSource(); $this->processValidationResult($import->validateSource($source), $resultBlock); } catch (\Magento\Framework\Exception\LocalizedException $e) { $resultBlock->addError($e->getMessage()); @@ -72,6 +72,7 @@ public function execute() * @param bool $validationResult * @param Result $resultBlock * @return void + * @throws \Magento\Framework\Exception\LocalizedException */ private function processValidationResult($validationResult, $resultBlock) { @@ -109,6 +110,8 @@ private function processValidationResult($validationResult, $resultBlock) } /** + * Provides import model. + * * @return Import * @deprecated 100.1.0 */ @@ -128,6 +131,7 @@ private function getImport() * * @param Result $resultBlock * @return void + * @throws \Magento\Framework\Exception\LocalizedException */ private function addMessageToSkipErrors(Result $resultBlock) { @@ -148,6 +152,7 @@ private function addMessageToSkipErrors(Result $resultBlock) * * @param Result $resultBlock * @return void + * @throws \Magento\Framework\Exception\LocalizedException */ private function addMessageForValidResult(Result $resultBlock) { @@ -166,6 +171,7 @@ private function addMessageForValidResult(Result $resultBlock) * * @param Result $resultBlock * @return void + * @throws \Magento\Framework\Exception\LocalizedException */ private function collectErrors(Result $resultBlock) { diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index b5e8220e0e9b0..f336e0d41e089 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -19,6 +19,7 @@ * @method string getBehavior() getBehavior() * @method \Magento\ImportExport\Model\Import setEntity() setEntity(string $value) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @since 100.0.2 */ class Import extends \Magento\ImportExport\Model\AbstractModel @@ -268,6 +269,7 @@ protected function _getEntityAdapter() * * @param string $sourceFile Full path to source file * @return \Magento\ImportExport\Model\Import\AbstractSource + * @throws \Magento\Framework\Exception\FileSystemException */ protected function _getSourceAdapter($sourceFile) { @@ -283,6 +285,7 @@ protected function _getSourceAdapter($sourceFile) * * @param ProcessingErrorAggregatorInterface $validationResult * @return string[] + * @throws \Magento\Framework\Exception\LocalizedException */ public function getOperationResultMessages(ProcessingErrorAggregatorInterface $validationResult) { @@ -379,6 +382,7 @@ public function getEntity() * Returns number of checked entities. * * @return int + * @throws \Magento\Framework\Exception\LocalizedException */ public function getProcessedEntitiesCount() { @@ -389,6 +393,7 @@ public function getProcessedEntitiesCount() * Returns number of checked rows. * * @return int + * @throws \Magento\Framework\Exception\LocalizedException */ public function getProcessedRowsCount() { @@ -443,6 +448,8 @@ public function importSource() } /** + * Process import. + * * @return bool * @throws \Magento\Framework\Exception\LocalizedException */ @@ -455,6 +462,7 @@ protected function processImport() * Import possibility getter. * * @return bool + * @throws \Magento\Framework\Exception\LocalizedException */ public function isImportAllowed() { @@ -462,6 +470,8 @@ public function isImportAllowed() } /** + * Provides error aggregator. + * * @return ProcessingErrorAggregatorInterface * @throws \Magento\Framework\Exception\LocalizedException */ @@ -471,7 +481,7 @@ public function getErrorAggregator() } /** - * Move uploaded file and create source adapter instance. + * Move uploaded file. * * @throws \Magento\Framework\Exception\LocalizedException * @return string Source file path @@ -523,14 +533,27 @@ public function uploadSource() } $this->_removeBom($sourceFile); $this->createHistoryReport($sourceFileRelative, $entity, $extension, $result); - // trying to create source adapter for file and catch possible exception to be convinced in its adequacy + return $sourceFile; + } + + /** + * Move uploaded file and provide source instance. + * + * @return Import\AbstractSource + * @throws \Magento\Framework\Exception\FileSystemException + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function uploadFileAndGetSource() + { + $sourceFile = $this->uploadSource(); try { - $this->_getSourceAdapter($sourceFile); + $source = $this->_getSourceAdapter($sourceFile); } catch (\Exception $e) { - $this->_varDirectory->delete($sourceFileRelative); + $this->_varDirectory->delete($this->_varDirectory->getRelativePath($sourceFile)); throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage())); } - return $sourceFile; + + return $source; } /** @@ -538,6 +561,7 @@ public function uploadSource() * * @param string $sourceFile * @return $this + * @throws \Magento\Framework\Exception\FileSystemException */ protected function _removeBom($sourceFile) { @@ -557,6 +581,7 @@ protected function _removeBom($sourceFile) * * @param \Magento\ImportExport\Model\Import\AbstractSource $source * @return bool + * @throws \Magento\Framework\Exception\LocalizedException */ public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource $source) { @@ -595,6 +620,7 @@ public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource * Invalidate indexes by process codes. * * @return $this + * @throws \Magento\Framework\Exception\LocalizedException */ public function invalidateIndex() { @@ -661,6 +687,7 @@ public function getEntityBehaviors() * ) * * @return array + * @throws \Magento\Framework\Exception\LocalizedException */ public function getUniqueEntityBehaviors() { @@ -710,9 +737,9 @@ public function isReportEntityType($entity = null) /** * Create history report * + * @param string $sourceFileRelative * @param string $entity * @param string $extension - * @param string $sourceFileRelative * @param array $result * @return $this * @throws \Magento\Framework\Exception\LocalizedException @@ -751,6 +778,7 @@ protected function createHistoryReport($sourceFileRelative, $entity, $extension * Get count of created items * * @return int + * @throws \Magento\Framework\Exception\LocalizedException */ public function getCreatedItemsCount() { @@ -761,6 +789,7 @@ public function getCreatedItemsCount() * Get count of updated items * * @return int + * @throws \Magento\Framework\Exception\LocalizedException */ public function getUpdatedItemsCount() { @@ -771,6 +800,7 @@ public function getUpdatedItemsCount() * Get count of deleted items * * @return int + * @throws \Magento\Framework\Exception\LocalizedException */ public function getDeletedItemsCount() { diff --git a/app/code/Magento/ImportExport/Model/Import/Source/Zip.php b/app/code/Magento/ImportExport/Model/Import/Source/Zip.php index 7c13e47957cda..6fa87ab5d5c4d 100644 --- a/app/code/Magento/ImportExport/Model/Import/Source/Zip.php +++ b/app/code/Magento/ImportExport/Model/Import/Source/Zip.php @@ -25,13 +25,14 @@ public function __construct( $options ) { $zip = new \Magento\Framework\Archive\Zip(); - $file = $zip->unpack( - $directory->getRelativePath($file), - $directory->getRelativePath(preg_replace('/\.zip$/i', '.csv', $file)) + $csvFile = $zip->unpack( + $file, + preg_replace('/\.zip$/i', '.csv', $file) ); - if (!$file) { + if (!$csvFile) { throw new ValidatorException(__('Sorry, but the data is invalid or the file is not uploaded.')); } - parent::__construct($file, $directory, $options); + $directory->delete($directory->getRelativePath($file)); + parent::__construct($csvFile, $directory, $options); } } diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/ValidateTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/ValidateTest.php index 552a23a0c1fd5..9afce0ed10bcd 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/ValidateTest.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/ValidateTest.php @@ -17,12 +17,15 @@ class ValidateTest extends \Magento\TestFramework\TestCase\AbstractBackendContro /** * @dataProvider validationDataProvider * @param string $fileName + * @param string $mimeType * @param string $message * @param string $delimiter + * @throws \Magento\Framework\Exception\FileSystemException * @backupGlobals enabled * @magentoDbIsolation enabled + * @SuppressWarnings(PHPMD.Superglobals) */ - public function testValidationReturn($fileName, $message, $delimiter) + public function testValidationReturn(string $fileName, string $mimeType, string $message, string $delimiter) { $validationStrategy = ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR; @@ -50,7 +53,7 @@ public function testValidationReturn($fileName, $message, $delimiter) $_FILES = [ 'import_file' => [ 'name' => $fileName, - 'type' => 'text/csv', + 'type' => $mimeType, 'tmp_name' => $target, 'error' => 0, 'size' => filesize($target) @@ -84,24 +87,34 @@ public function validationDataProvider() return [ [ 'file_name' => 'catalog_product.csv', + 'mime-type' => 'text/csv', 'message' => 'File is valid', 'delimiter' => ',', ], [ 'file_name' => 'test.txt', + 'mime-type' => 'text/csv', 'message' => '\'txt\' file extension is not supported', 'delimiter' => ',', ], [ 'file_name' => 'incorrect_catalog_product_comma.csv', + 'mime-type' => 'text/csv', 'message' => 'Download full report', 'delimiter' => ',', ], [ 'file_name' => 'incorrect_catalog_product_semicolon.csv', + 'mime-type' => 'text/csv', 'message' => 'Download full report', 'delimiter' => ';', ], + [ + 'file_name' => 'catalog_product.zip', + 'mime-type' => 'application/zip', + 'message' => 'File is valid', + 'delimiter' => ',', + ], ]; } } diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/catalog_product.zip b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/catalog_product.zip new file mode 100644 index 0000000000000000000000000000000000000000..812beae22b786dc74cf22d914869a811e4be1e8b GIT binary patch literal 955 zcmWIWW@Zs#W?<l8*cck<Yk%>>Cw?IBAqNA4FarZaa$-qhPJViPK~a86X>y5Pa&g(# z(6jF@8}RJ^EOPZ6<67312OKdw3LY{pT2pG>ZKApHvwU^+9JSo<N0+;(E&aIt@8-!D zudguK$iHAqB40%Z&#Z>4A~oXC*J|cDY;8;Yz}Pq?jz!%<U{gU<e(i+05!+r^%-Q<> zYevi)-_wR2l?;U!GL@wQ7xnI9K6EfPco%=&p2Usu64&O`rpPY$i_sL^&ZzG8{z}4{ z)`BqRZ)@BYjF>Y%r(BrT+<L~2)!6q%+x(A9wQ?L~c{A;+Ra+PTIJsMldjppz`-G-D zIrV`F0m>ULihHIW3%8hG^TO!hiIZG&cWhC;=aD$e{H~&J&>}xR@xo*GW(JyBT<qze z_KEwXov>=+-Kyhkb5o2x&#@XzWv=Z$=E?Nve(B2lZ^Li$x(6}7xg#xS@#3VgTKX>r z_s=bMe_V13UBqr~?{IA4PAU1)xIRH)<<(b`N51Z1^b+2Z@g^+d*_2=5S!=f}IrD6H z-de>=H#F^zeSENF<?WRf(*rew)!mso|L!>ETNR(gV^&)D&#$fj6(=Wu2CG*olT6>5 zeJ2BVt-5S3w8ZR-#f#R~DRxX=vwyAQTlQB=nXyrCs`<M&T|KSQ_2GXm*3_@q@?rXk zBxCbv%kwwp8y9AmXnRlAwLR72eRTeZ$-OR<yzQEjgRVbWs&vLY{bKmcJ%-b_h;Mij zWRu7~SIgfwYkM49P~5ty5xbX_NZSNvrH9=(;j8M`U1OW?<i_#z+td}|d;UmpTC&J5 z=e`(oOf}XmLT(A)*-zWfnTo{i<7_>l9Nl3$H+1r)-xCf9CC{wB|ETSt8+YE`&S}M3 z()C}z=eS$=iLLt77XH<5W&cf&)QOWgRRcDao!wXWbx+<r^YyELz1@BN?C$V<m)gkR zOFrG?ets@<>+a{aDJQE=+}*p~C~4|TNvE$TzwZ0>AXjGYiC2IB9gUlItG4Lsbd%2A zmNWNcUHzl<S>{zG=hr=AzCV+Vuko)^GFWK4jN$BQnFU8y9<99fda4fl&$F{-@=M=e zll^cup5gze*uSs(8}fxdd~cLHT9@!g`oZjahPrcq<bFI;{BZVk_<zP9@&VqAO!myU za*zrz4}pL}!;(f2jU_*EF(`m!7#JBO7#et@3JlV&FgA!UYcvDVP=0_nD;q=&BSR{X K;Q-8{3=9Cp%do}( literal 0 HcmV?d00001 diff --git a/lib/internal/Magento/Framework/Archive/Zip.php b/lib/internal/Magento/Framework/Archive/Zip.php index 908b045c15397..c41f8b28ce348 100644 --- a/lib/internal/Magento/Framework/Archive/Zip.php +++ b/lib/internal/Magento/Framework/Archive/Zip.php @@ -52,15 +52,19 @@ public function pack($source, $destination) public function unpack($source, $destination) { $zip = new \ZipArchive(); - $zip->open($source); - $filename = $this->filterRelativePaths($zip->getNameIndex(0) ?: ''); - if ($filename) { - $zip->extractTo(dirname($destination), $filename); - rename(dirname($destination).'/'.$filename, $destination); + if ($zip->open($source) === true) { + $filename = $this->filterRelativePaths($zip->getNameIndex(0) ?: ''); + if ($filename) { + $zip->extractTo(dirname($destination), $filename); + rename(dirname($destination).'/'.$filename, $destination); + } else { + $destination = ''; + } + $zip->close(); } else { $destination = ''; } - $zip->close(); + return $destination; } From d225cef871e16937df45f3ea138debed41aadf8b Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 18 Oct 2018 10:45:49 +0300 Subject: [PATCH 0240/1158] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- .../Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index 5e36a8f776628..7ece18fb863b7 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -22,7 +22,7 @@ <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> <element name="createNewOrder" type="button" selector=".page-actions-buttons button#add" timeout="30"/> - <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)" timeout="30"/> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> <element name="viewBookmarkDropdown" type="button" selector="div.admin__data-grid-action-bookmarks button" timeout="30"/> From 690dd08208b8bbb98f747e31356a72334d1f7f8c Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 18 Oct 2018 15:01:37 +0300 Subject: [PATCH 0241/1158] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- ...rontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml | 2 +- .../Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml index 32d141d7e533e..f263ff85dd737 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml @@ -72,7 +72,7 @@ <conditionalClick selector="{{CheckoutPaymentSection.ProductOptionsByProductItemName($$createProduct.name$$)}}" dependentSelector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($$createProduct.name$$)}}" visible="false" stepKey="exposeProductOptions"/> <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($$createProduct.name$$)}}" userInput="{{ProductOptionValueDropdownLongTitle1.title}}" stepKey="seeProductOptionValueDropdown1Input1"/> - + <click selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> <!-- Place Order --> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml index 9dd2127fa28b2..99ba9cf3fcb67 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml @@ -19,6 +19,9 @@ <group value="customer"/> <group value="create"/> </annotations> + <before> + <magentoCLI command="indexer:reindex customer_grid" stepKey="reindexCustomerGrid"/> + </before> <after> <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> </after> From eaa459f90b25bc5777f889a0fc3c3c447aea9711 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Thu, 18 Oct 2018 09:11:46 -0500 Subject: [PATCH 0242/1158] MAGETWO-95642: Import error --- app/code/Magento/ImportExport/Model/Import.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index f336e0d41e089..410a4e6fee990 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -8,6 +8,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\HTTP\Adapter\FileTransferFactory; +use Magento\Framework\Stdlib\DateTime\DateTime; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; @@ -168,6 +169,16 @@ class Import extends \Magento\ImportExport\Model\AbstractModel */ protected $_filesystem; + /** + * @var History + */ + private $importHistoryModel; + + /** + * @var DateTime + */ + private $localeDate; + /** * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Filesystem $filesystem @@ -182,7 +193,7 @@ class Import extends \Magento\ImportExport\Model\AbstractModel * @param Source\Import\Behavior\Factory $behaviorFactory * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry * @param History $importHistoryModel - * @param \Magento\Framework\Stdlib\DateTime\DateTime + * @param DateTime $localeDate * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -200,7 +211,7 @@ public function __construct( \Magento\ImportExport\Model\Source\Import\Behavior\Factory $behaviorFactory, \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry, \Magento\ImportExport\Model\History $importHistoryModel, - \Magento\Framework\Stdlib\DateTime\DateTime $localeDate, + DateTime $localeDate, array $data = [] ) { $this->_importExportData = $importExportData; From 0fc8a1f405b4b63c81715f3549a08e63b4ea196b Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Wed, 17 Oct 2018 16:27:14 -0500 Subject: [PATCH 0243/1158] MAGETWO-95620: Path Validation in Templates - Resolve real directory of template file before validating path in allowed directories - Update unit test to mock this new dependency --- .../View/Element/Template/File/Validator.php | 14 +++++-- .../Element/Template/File/ValidatorTest.php | 39 +++++++++++-------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php b/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php index 4b4e7e1bad467..5f18c78e3a0ad 100644 --- a/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php +++ b/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php @@ -7,10 +7,10 @@ use \Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Component\ComponentRegistrar; +use \Magento\Framework\Filesystem\Driver\File as FileDriver; /** * Class Validator - * @package Magento\Framework\View\Element\Template\File */ class Validator { @@ -68,6 +68,11 @@ class Validator */ protected $_compiledDir; + /** + * @var FileDriver + */ + private $fileDriver; + /** * Class constructor * @@ -75,12 +80,14 @@ class Validator * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfigInterface * @param ComponentRegistrar $componentRegistrar * @param string|null $scope + * @param FileDriver|null $fileDriver */ public function __construct( \Magento\Framework\Filesystem $filesystem, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfigInterface, ComponentRegistrar $componentRegistrar, - $scope = null + $scope = null, + ?FileDriver $fileDriver = null ) { $this->_filesystem = $filesystem; $this->_isAllowSymlinks = $scopeConfigInterface->getValue(self::XML_PATH_TEMPLATE_ALLOW_SYMLINK, $scope); @@ -88,6 +95,7 @@ public function __construct( $this->moduleDirs = $componentRegistrar->getPaths(ComponentRegistrar::MODULE); $this->_compiledDir = $this->_filesystem->getDirectoryRead(DirectoryList::TMP_MATERIALIZATION_DIR) ->getAbsolutePath(); + $this->fileDriver = $fileDriver ?: \Magento\Framework\App\ObjectManager::getInstance()->get(FileDriver::class); } /** @@ -128,7 +136,7 @@ protected function isPathInDirectories($path, $directories) $directories = (array)$directories; } foreach ($directories as $directory) { - if (0 === strpos($path, $directory)) { + if (0 === strpos($this->fileDriver->getRealPath($path), $directory)) { return true; } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php index 28d58f4685e80..7a3578993f375 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php @@ -20,21 +20,21 @@ class ValidatorTest extends \PHPUnit\Framework\TestCase * * @var \Magento\Framework\View\Element\Template\File\Validator */ - private $_validator; + private $validator; /** * Mock for view file system * * @var \Magento\Framework\FileSystem|\PHPUnit_Framework_MockObject_MockObject */ - private $_fileSystemMock; + private $fileSystemMock; /** * Mock for scope config * * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $_scopeConfigMock; + private $scopeConfigMock; /** * Mock for root directory reader @@ -62,12 +62,12 @@ class ValidatorTest extends \PHPUnit\Framework\TestCase */ protected function setUp() { - $this->_fileSystemMock = $this->createMock(\Magento\Framework\Filesystem::class); - $this->_scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $this->fileSystemMock = $this->createMock(\Magento\Framework\Filesystem::class); + $this->scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); $this->rootDirectoryMock = $this->createMock(\Magento\Framework\Filesystem\Directory\ReadInterface::class); $this->compiledDirectoryMock = $this->createMock(\Magento\Framework\Filesystem\Directory\ReadInterface::class); - $this->_fileSystemMock->expects($this->any()) + $this->fileSystemMock->expects($this->any()) ->method('getDirectoryRead') ->will($this->returnValueMap( [ @@ -91,10 +91,18 @@ protected function setUp() ] ) ); - $this->_validator = new \Magento\Framework\View\Element\Template\File\Validator( - $this->_fileSystemMock, - $this->_scopeConfigMock, - $this->componentRegistrar + + $fileDriverMock = $this->createMock(\Magento\Framework\Filesystem\Driver\File::class); + $fileDriverMock->expects($this->any()) + ->method('getRealPath') + ->willReturnArgument(0); + + $this->validator = new \Magento\Framework\View\Element\Template\File\Validator( + $this->fileSystemMock, + $this->scopeConfigMock, + $this->componentRegistrar, + null, + $fileDriverMock ); } @@ -103,23 +111,22 @@ protected function setUp() * * @param string $file * @param bool $expectedResult - * - * @dataProvider testIsValidDataProvider - * * @return void + * + * @dataProvider isValidDataProvider */ public function testIsValid($file, $expectedResult) { $this->rootDirectoryMock->expects($this->any())->method('isFile')->will($this->returnValue(true)); - $this->assertEquals($expectedResult, $this->_validator->isValid($file)); + $this->assertEquals($expectedResult, $this->validator->isValid($file)); } /** * Data provider for testIsValid * - * @return [] + * @return array */ - public function testIsValidDataProvider() + public function isValidDataProvider() { return [ 'empty' => ['', false], From 09c47a1b36d905c01a3084f3bd48d21923228356 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Thu, 18 Oct 2018 12:38:34 -0500 Subject: [PATCH 0244/1158] MQE-1187: Fix MFTF skipped tests - Heavy Refactor work on CreateAnAdminOrderUsingBraintreePaymentTest1, test was redefining existing action-groups for no good reason. --- .../ActionGroup/CreateNewOrderActionGroup.xml | 29 +------------ .../Test/Mftf/Data/BraintreeData.xml | 2 +- ...AnAdminOrderUsingBraintreePaymentTest1.xml | 43 +++++++++++++------ 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml index ee7158c2b63f7..17d634c009b3e 100644 --- a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml @@ -8,28 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="CreateNewOrderActionGroup"> - <click stepKey="createNewOrder" selector="{{NewOrderSection.createNewOrder}}"/> - <waitForPageLoad stepKey="waitForCustomersList" time="3"/> - <click stepKey="chooseCustomer" selector="{{NewOrderSection.customer}}"/> - <waitForPageLoad stepKey="waitForOrderPage" time="3"/> - <click stepKey="addProducts" selector="{{NewOrderSection.addProducts}}"/> - <waitForPageLoad stepKey="waitForProducts" time="3"/> - <click stepKey="chooseProducts" selector="{{NewOrderSection.chooseProduct}}"/> - <waitForPageLoad stepKey="waitForProductChoose" time="3"/> - <click stepKey="addSelectedProduct" selector="{{NewOrderSection.addSelectedProduct}}"/> - <waitForAjaxLoad stepKey="waitForChoose" time="3"/> - <click stepKey="openAddresses" selector="{{NewOrderSection.openAddresses}}"/> - <click stepKey="chooseAddress" selector="{{NewOrderSection.chooseAddress}}"/> - <fillField stepKey="fillState" selector="{{NewOrderSection.state}}" userInput="Yerevan"/> - <scrollTo stepKey="scrollTo" selector="#order-methods"/> - <waitForPageLoad stepKey="waitForMethods" time="3"/> - <click stepKey="startJSMethodExecution" selector="{{NewOrderSection.openShippingMethods}}"/> - <waitForPageLoad stepKey="waitForJSMethodExecution" time="3"/> - <click stepKey="openShippingMethods" selector="{{NewOrderSection.openShippingMethods}}"/> - <waitForPageLoad stepKey="waitForShippingMethods" time="3"/> - <click stepKey="chooseShippingMethods" selector="{{NewOrderSection.shippingMethod}}"/> - <waitForPageLoad stepKey="waitForShippingMethodChoose" time="4"/> + <actionGroup name="useBraintreeForMasterCard"> <click stepKey="chooseBraintree" selector="{{NewOrderSection.creditCardBraintree}}"/> <waitForPageLoad stepKey="waitForBraintreeConfigs" time="5"/> <click stepKey="openCardTypes" selector="{{NewOrderSection.openCardTypes}}"/> @@ -56,11 +35,5 @@ <fillField stepKey="fillCVV" selector="{{NewOrderSection.cvv}}" userInput="{{PaymentAndShippingInfo.cvv}}"/> <wait stepKey="waitForFillCVV" time="1"/> <switchToIFrame stepKey="switchBackFromCVV"/> - - <click stepKey="submitOrder" selector="{{NewOrderSection.submitOrder}}"/> - <waitForPageLoad stepKey="waitForSaveConfig" time="5"/> - <waitForElementVisible selector="{{NewOrderSection.successMessage}}" stepKey="waitForSuccessMessage" time="1"/> - </actionGroup> - </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml index 8f2588a6effa5..61be90076539e 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml @@ -128,7 +128,7 @@ <data key="firstName">John</data> <data key="lastName">Smith</data> <data key="password">admin123</data> - <data key="email">mail@mail.com</data> + <data key="email" unique="prefix">mail@mail.com</data> </entity> <entity name="PaymentAndShippingInfo" type="data"> diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml index df2e98816f0d3..35829071407e0 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml @@ -17,9 +17,6 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-93677"/> <group value="braintree"/> - <skip> - <issueId value="MQE-1187" /> - </skip> </annotations> @@ -28,11 +25,13 @@ <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> <!--CreateNewProduct--> - <actionGroup ref="CreateNewProductActionGroup" stepKey="CreateNewProduct"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> <!--Create New Customer--> - <actionGroup ref="CreateCustomerActionGroup" stepKey="CreateCustomer"/> - + <createData stepKey="createCustomer" entity="Simple_US_Customer"/> </before> @@ -48,15 +47,35 @@ <actionGroup ref="AdminCreateUserAction" stepKey="AdminCreateNewUser"/> <!--SignOut--> - <actionGroup ref="SignOut" stepKey="signOutFromAdmin"/> + <actionGroup ref="logout" stepKey="signOutFromAdmin"/> <!--SignIn New User--> <actionGroup ref="LoginNewUser" stepKey="signInNewUser"/> <waitForPageLoad stepKey="waitForLogin" time="3"/> <!--Create New Order--> - <actionGroup ref="CreateNewOrderActionGroup" stepKey="createNewOrder"/> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrder"> + <argument name="customer" value="Simple_US_Customer"/> + </actionGroup> + + <actionGroup ref="addSimpleProductToOrder" stepKey="addProduct"> + <argument name="product" value="_defaultProduct"/> + </actionGroup> + + <actionGroup ref="fillOrderCustomerInformation" stepKey="fillCustomerAddress"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="address" value="US_Address_TX"/> + </actionGroup> + + <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping"/> + + <waitForPageLoad stepKey="waitForShippingToFinish"/> + + <actionGroup ref="useBraintreeForMasterCard" stepKey="selectCardWithBraintree"/> + <click stepKey="submitOrder" selector="{{NewOrderSection.submitOrder}}"/> + <waitForPageLoad stepKey="waitForSaveConfig" time="5"/> + <waitForElementVisible selector="{{NewOrderSection.successMessage}}" stepKey="waitForSuccessMessage" time="1"/> <after> <!--SignOut--> @@ -64,14 +83,10 @@ <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> <!--Delete Product--> - <actionGroup ref="DeleteProductActionGroup" stepKey="DeleteAllProducts"> - <argument name="productName" value="NewProductData.ProductName"/> - </actionGroup> + <deleteData stepKey="deleteProduct" createDataKey="createProduct"/> <!--Delete Customer--> - <actionGroup ref="DeleteCustomerActionGroup" stepKey="DeleteCustomer"> - <argument name="lastName" value="NewCustomerData.LastName"/> - </actionGroup> + <deleteData stepKey="deleteCustomer" createDataKey="createCustomer"/> <!--Delete User --> <actionGroup ref="GoToAllUsers" stepKey="GoBackToAllUsers"/> From 4870075a69904028141b9c02b53aeacf95c1c22c Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 18 Oct 2018 13:19:46 -0500 Subject: [PATCH 0245/1158] MAGETWO-95645: Custom file attribute works incorrect - fix tests --- app/code/Magento/Eav/Model/Attribute/Data/File.php | 6 +++--- lib/internal/Magento/Framework/Data/Form/Element/Text.php | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Eav/Model/Attribute/Data/File.php b/app/code/Magento/Eav/Model/Attribute/Data/File.php index 3d73ffa378232..1b2cac32598e1 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/File.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/File.php @@ -120,8 +120,7 @@ public function extractValue(RequestInterface $request) } /** - * Validate file by attribute validate rules - * Return array of errors + * Validate file by attribute validate rules and return array of errors * * @param array $value * @return string[] @@ -180,7 +179,8 @@ public function validateValue($value) $dir = $this->_directory->getAbsolutePath($this->getAttribute()->getEntityType()->getEntityTypeCode()); $fileData = [ 'size' => filesize($dir . $value), - 'name' => $value + 'name' => $value, + 'tmp_name' => $dir . $value ]; } diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Text.php b/lib/internal/Magento/Framework/Data/Form/Element/Text.php index b7b084310ed14..2f001eb10307b 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Text.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Text.php @@ -4,15 +4,13 @@ * See COPYING.txt for license details. */ -/** - * Form text element - * - * @author Magento Core Team <core@magentocommerce.com> - */ namespace Magento\Framework\Data\Form\Element; use Magento\Framework\Escaper; +/** + * Form text element + */ class Text extends AbstractElement { /** From d5e5c27b47506ebe455e672b74de20f6e93d1234 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Thu, 18 Oct 2018 13:58:32 -0500 Subject: [PATCH 0246/1158] MQE-1187: Fix MFTF skipped tests - Unskipping NewProductsListWidgetDownloadableProductTest --- .../Mftf/Test/NewProductsListWidgetDownloadableProductTest.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Downloadable/Test/Mftf/Test/NewProductsListWidgetDownloadableProductTest.xml b/app/code/Magento/Downloadable/Test/Mftf/Test/NewProductsListWidgetDownloadableProductTest.xml index 1a9ad271d62c7..4864d11c884bc 100644 --- a/app/code/Magento/Downloadable/Test/Mftf/Test/NewProductsListWidgetDownloadableProductTest.xml +++ b/app/code/Magento/Downloadable/Test/Mftf/Test/NewProductsListWidgetDownloadableProductTest.xml @@ -18,9 +18,6 @@ <testCaseId value="MC-124"/> <group value="Downloadable"/> <group value="WYSIWYGDisabled"/> - <skip> - <issueId value="MQE-1187"/> - </skip> </annotations> <!-- A Cms page containing the New Products Widget gets created here via extends --> From ee7f0c6f86f701e608c4f3a61ca4a4c9a0e4f864 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Thu, 18 Oct 2018 17:14:54 -0500 Subject: [PATCH 0247/1158] MAGETWO-95636: Upload Extension Validation - Add validation to file extension before retrieving it from remote server - Clean up some code to remove cyclomatic complexity - Account for changes in unit test --- .../Model/Import/Uploader.php | 36 ++++++++++--------- .../Test/Unit/Model/Import/UploaderTest.php | 13 +++++-- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php b/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php index e7ffe408cc732..cca31b97e6b6d 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php @@ -101,7 +101,7 @@ class Uploader extends \Magento\MediaStorage\Model\File\Uploader * @param \Magento\MediaStorage\Model\File\Validator\NotProtectedExtension $validator * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Framework\Filesystem\File\ReadFactory $readFactory - * @param null $filePath + * @param string|null $filePath * @throws \Magento\Framework\Exception\LocalizedException */ public function __construct( @@ -146,20 +146,25 @@ public function init() * @param string $fileName * @param bool $renameFileOff * @return array + * + * @throws \Magento\Framework\Exception\LocalizedException */ public function move($fileName, $renameFileOff = false) { if ($renameFileOff) { $this->setAllowRenameFiles(false); } + + if ($this->getTmpDir()) { + $filePath = $this->getTmpDir() . '/'; + } else { + $filePath = ''; + } + if (preg_match('/\bhttps?:\/\//i', $fileName, $matches)) { $url = str_replace($matches[0], '', $fileName); - - if ($matches[0] === $this->httpScheme) { - $read = $this->_readFactory->create($url, DriverPool::HTTP); - } else { - $read = $this->_readFactory->create($url, DriverPool::HTTPS); - } + $driver = $matches[0] === $this->httpScheme ? DriverPool::HTTP : DriverPool::HTTPS; + $read = $this->_readFactory->create($url, $driver); //only use filename (for URI with query parameters) $parsedUrlPath = parse_url($url, PHP_URL_PATH); @@ -170,11 +175,13 @@ public function move($fileName, $renameFileOff = false) } } - if ($this->getTmpDir()) { - $filePath = $this->getTmpDir() . '/'; - } else { - $filePath = ''; + $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION); + if ($fileExtension && !$this->checkAllowedExtension($fileExtension)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('File extension \'%1\' is not a supported upload type', $fileExtension) + ); } + $fileName = preg_replace('/[^a-z0-9\._-]+/i', '', $fileName); $filePath = $this->_directory->getRelativePath($filePath . $fileName); $this->_directory->writeFile( @@ -183,11 +190,6 @@ public function move($fileName, $renameFileOff = false) ); } - if ($this->getTmpDir()) { - $filePath = $this->getTmpDir() . '/'; - } else { - $filePath = ''; - } $filePath = $this->_directory->getRelativePath($filePath . $fileName); $this->_setUploadFile($filePath); $destDir = $this->_directory->getAbsolutePath($this->getDestDir()); @@ -353,7 +355,7 @@ protected function _moveFile($tmpPath, $destPath) } /** - * {@inheritdoc} + * @inheritdoc */ protected function chmod($file) { diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/UploaderTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/UploaderTest.php index 262593377aa2c..f734596de014b 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/UploaderTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/UploaderTest.php @@ -93,14 +93,14 @@ protected function setUp() $this->filesystem, $this->readFactory, ]) - ->setMethods(['_setUploadFile', 'save', 'getTmpDir']) + ->setMethods(['_setUploadFile', 'save', 'getTmpDir', 'checkAllowedExtension']) ->getMock(); } /** * @dataProvider moveFileUrlDataProvider */ - public function testMoveFileUrl($fileUrl, $expectedHost, $expectedFileName) + public function testMoveFileUrl($fileUrl, $expectedHost, $expectedFileName, $checkAllowedExtension) { $destDir = 'var/dest/dir'; $expectedRelativeFilePath = $expectedFileName; @@ -128,6 +128,9 @@ public function testMoveFileUrl($fileUrl, $expectedHost, $expectedFileName) $this->uploader->expects($this->once())->method('_setUploadFile')->will($this->returnSelf()); $this->uploader->expects($this->once())->method('save')->with($destDir . '/' . $expectedFileName) ->willReturn(['name' => $expectedFileName, 'path' => 'absPath']); + $this->uploader->expects($this->exactly($checkAllowedExtension)) + ->method('checkAllowedExtension') + ->willReturn(true); $this->uploader->setDestDir($destDir); $result = $this->uploader->move($fileUrl); @@ -224,31 +227,37 @@ public function moveFileUrlDataProvider() '$fileUrl' => 'http://test_uploader_file', '$expectedHost' => 'test_uploader_file', '$expectedFileName' => 'test_uploader_file', + '$checkAllowedExtension' => 0 ], [ '$fileUrl' => 'https://!:^&`;file', '$expectedHost' => '!:^&`;file', '$expectedFileName' => 'file', + '$checkAllowedExtension' => 0 ], [ '$fileUrl' => 'https://www.google.com/image.jpg', '$expectedHost' => 'www.google.com/image.jpg', '$expectedFileName' => 'image.jpg', + '$checkAllowedExtension' => 1 ], [ '$fileUrl' => 'https://www.google.com/image.jpg?param=1', '$expectedHost' => 'www.google.com/image.jpg?param=1', '$expectedFileName' => 'image.jpg', + '$checkAllowedExtension' => 1 ], [ '$fileUrl' => 'https://www.google.com/image.jpg?param=1¶m=2', '$expectedHost' => 'www.google.com/image.jpg?param=1¶m=2', '$expectedFileName' => 'image.jpg', + '$checkAllowedExtension' => 1 ], [ '$fileUrl' => 'http://www.google.com/image.jpg?param=1¶m=2', '$expectedHost' => 'www.google.com/image.jpg?param=1¶m=2', '$expectedFileName' => 'image.jpg', + '$checkAllowedExtension' => 1 ], ]; } From 2e426e872ace021a6fcc86a523b297ae713fe5fd Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Fri, 19 Oct 2018 09:48:08 +0300 Subject: [PATCH 0248/1158] MAGETWO-92182: JS Templates Limitations --- .../Checkout/view/frontend/web/js/view/form/element/email.js | 3 +++ app/code/Magento/Ui/view/base/web/js/form/element/abstract.js | 3 +++ app/code/Magento/Ui/view/base/web/js/grid/editing/record.js | 3 +++ 3 files changed, 9 insertions(+) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js index 4a25778e754c7..9e18d4fca6dab 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js @@ -33,6 +33,9 @@ define([ listens: { email: 'emailHasChanged', emailFocused: 'validateEmail' + }, + ignoreTmpls: { + email: true } }, checkDelay: 2000, diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js b/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js index 8f1a75d2be0d4..3b98d2c93c7a9 100755 --- a/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js @@ -57,6 +57,9 @@ define([ '${ $.provider }:${ $.customScope ? $.customScope + "." : ""}data.validate': 'validate', 'isUseDefault': 'toggleUseDefault' }, + ignoreTmpls: { + value: true + }, links: { value: '${ $.provider }:${ $.dataScope }' diff --git a/app/code/Magento/Ui/view/base/web/js/grid/editing/record.js b/app/code/Magento/Ui/view/base/web/js/grid/editing/record.js index 18b3836113141..390aedf193b91 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/editing/record.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/editing/record.js @@ -50,6 +50,9 @@ define([ } } }, + ignoreTmpls: { + data: true + }, listens: { elems: 'updateFields', data: 'updateState' From c83a1caa6b1eb7182f235310938c22cfea7826f4 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Fri, 19 Oct 2018 11:58:59 +0300 Subject: [PATCH 0249/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- app/code/Magento/Catalog/etc/adminhtml/system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index 1b0fe4c85f617..7478fa2226454 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -206,7 +206,7 @@ <label>Images Upload Configuration</label> <field id="jpeg_quality" translate="label comment" type="text" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Quality</label> - <validate>validate-greater-than-zero validate-digits validate-range required-entry digits-range-1-100</validate> + <validate>validate-digits validate-digits-range digits-range-1-100 required-entry</validate> <comment>Jpeg quality for resized images 1-100%.</comment> </field> </group> From f672382b8e18a40163b53b2db60589ed388538b3 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Fri, 19 Oct 2018 12:24:28 +0300 Subject: [PATCH 0250/1158] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- ...StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml index 71aaf76c42e84..33181d6e920eb 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml @@ -71,6 +71,7 @@ <argument name="orderId" value="$grabOrderNumber"/> </actionGroup> <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <waitForPageLoad stepKey="waitForAdminOrderPageLoad"/> <scrollTo selector="{{AdminOrderTotalSection.subTotal}}" stepKey="scrollToOrderTotalSection"/> <see selector="{{AdminOrderTotalSection.subTotal}}" userInput="$0.00" stepKey="checkSubtotal"/> </test> From 6c1d07e06eb442a4108db0fe3007f95da2c409e2 Mon Sep 17 00:00:00 2001 From: Henryk Tews <h.tews@macopedia.pl> Date: Fri, 19 Oct 2018 13:14:10 +0200 Subject: [PATCH 0251/1158] Changed get product way in blocks with related products --- .../Magento/Catalog/Block/Product/ProductList/Crosssell.php | 2 +- app/code/Magento/Catalog/Block/Product/ProductList/Related.php | 2 +- app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Crosssell.php b/app/code/Magento/Catalog/Block/Product/ProductList/Crosssell.php index 0c547f81c85d6..043704a9f2bca 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Crosssell.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Crosssell.php @@ -25,7 +25,7 @@ class Crosssell extends \Magento\Catalog\Block\Product\AbstractProduct */ protected function _prepareData() { - $product = $this->_coreRegistry->registry('product'); + $product = $this->getProduct(); /* @var $product \Magento\Catalog\Model\Product */ $this->_itemCollection = $product->getCrossSellProductCollection()->addAttributeToSelect( diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Related.php b/app/code/Magento/Catalog/Block/Product/ProductList/Related.php index 219922f9e46d5..91e4161ce53b1 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Related.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Related.php @@ -81,7 +81,7 @@ public function __construct( */ protected function _prepareData() { - $product = $this->_coreRegistry->registry('product'); + $product = $this->getProduct(); /* @var $product \Magento\Catalog\Model\Product */ $this->_itemCollection = $product->getRelatedProductCollection()->addAttributeToSelect( diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php b/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php index 0d64ecc9bff90..ef38693a5454c 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php @@ -95,7 +95,7 @@ public function __construct( */ protected function _prepareData() { - $product = $this->_coreRegistry->registry('product'); + $product = $this->getProduct(); /* @var $product \Magento\Catalog\Model\Product */ $this->_itemCollection = $product->getUpSellProductCollection()->setPositionOrder()->addStoreFilter(); if ($this->moduleManager->isEnabled('Magento_Checkout')) { From c60761e9b7a4bb4b18c18929446f1c78f8a65a93 Mon Sep 17 00:00:00 2001 From: vtymchynskyi <vtymchynskyi@magento.com> Date: Fri, 19 Oct 2018 15:42:04 +0300 Subject: [PATCH 0252/1158] MAGETWO-95539: [2.3] Moving Category generate duplicate url_rewrite when 4th level category exist and is translated - Fixed url rewrites regeneration after category moving --- .../CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php index 8a70af213c612..fcdc21bedc5f8 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php @@ -64,15 +64,19 @@ public function afterChangeParent( Category $newParent, $afterCategoryId ) { + + $categoryStoreId = $category->getStoreId(); foreach ($category->getStoreIds() as $storeId) { $category->setStoreId($storeId); if (!$this->isGlobalScope($storeId)) { $this->updateCategoryUrlKeyForStore($category); + $category->unsUrlPath(); $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); $category->getResource()->saveAttribute($category, 'url_path'); $this->updateUrlPathForChildren($category); } } + $category->setStoreId($categoryStoreId); return $result; } From 93a2d716bf351f5ac48ba9b8bec000596eb6dc6b Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Fri, 19 Oct 2018 11:02:58 -0500 Subject: [PATCH 0253/1158] MAGETWO-95391: Widget Escaping - Add suppression for new block aware rule --- app/code/Magento/Widget/Block/Adminhtml/Widget.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget.php b/app/code/Magento/Widget/Block/Adminhtml/Widget.php index dad318f163b4b..33e6109b769db 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget.php @@ -16,6 +16,8 @@ class Widget extends \Magento\Backend\Block\Widget\Form\Container { /** * @inheritdoc + * + * @SuppressWarnings(PHPMD.RequestAwareBlockMethod) */ protected function _construct() { From 61453702309784edb31ec24b595986c5cf3d062e Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Fri, 19 Oct 2018 11:31:23 -0500 Subject: [PATCH 0254/1158] MQE-1187: Fix MFTF skipped tests - Removing AdminGWS features from actionGroup --- .../User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml index b1ac0820923d9..14f41cefa7d01 100644 --- a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml @@ -18,20 +18,15 @@ <actionGroup name="AdminCreateRole"> <arguments> <argument name="role" type="string" defaultValue=""/> - <argument name="resource" type="string" defaultValue="All"/> <argument name="scope" type="string" defaultValue="Custom"/> - <argument name="websites" type="string" defaultValue="Main Website"/> </arguments> <click selector="{{AdminCreateRoleSection.create}}" stepKey="clickToAddNewRole"/> <fillField selector="{{AdminCreateRoleSection.name}}" userInput="{{role.name}}" stepKey="setRoleName"/> <fillField stepKey="setPassword" selector="{{AdminCreateRoleSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> <click selector="{{AdminCreateRoleSection.roleResources}}" stepKey="clickToOpenRoleResources"/> <waitForPageLoad stepKey="waitForRoleResourcePage" time="5"/> - <click selector="{{AdminCreateRoleSection.roleResource}}" stepKey="clickToExpandResourceAccess"/> - <click selector="{{AdminCreateRoleSection.resourceValue(scope)}}" stepKey="clickToSelectResourceAccess"/> <click selector="{{AdminCreateRoleSection.roleScope}}" stepKey="clickToExpandScopeAccess"/> <click selector="{{AdminCreateRoleSection.scopeValue(resource)}}" stepKey="clickToSelectScopeAccess"/> - <click selector="{{AdminCreateRoleSection.website(websites)}}" stepKey="clickToSelectWebsite"/> <click selector="{{AdminCreateRoleSection.save}}" stepKey="clickToSaveRole"/> <waitForPageLoad stepKey="waitForPageLoad" time="10"/> <see userInput="You saved the role." stepKey="seeSuccessMessage" /> From bcd2f80e68cc86ac1aba0dd2a3e243f3b1fc591b Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Fri, 19 Oct 2018 12:24:08 -0500 Subject: [PATCH 0255/1158] MAGETWO-95636: Upload Extension Validation - Align messaging of exception with existing validation --- .../Magento/CatalogImportExport/Model/Import/Uploader.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php b/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php index cca31b97e6b6d..087a12452bef4 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php @@ -177,9 +177,7 @@ public function move($fileName, $renameFileOff = false) $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION); if ($fileExtension && !$this->checkAllowedExtension($fileExtension)) { - throw new \Magento\Framework\Exception\LocalizedException( - __('File extension \'%1\' is not a supported upload type', $fileExtension) - ); + throw new \Magento\Framework\Exception\LocalizedException(__('Disallowed file type.')); } $fileName = preg_replace('/[^a-z0-9\._-]+/i', '', $fileName); From 7051b70ea838191ebf1044b417cbcd58176f950e Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Fri, 19 Oct 2018 14:15:56 -0500 Subject: [PATCH 0256/1158] MQE-1187: Fix MFTF skipped tests - Fixing argument delta --- .../Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml index 14f41cefa7d01..d8a6a60299f8e 100644 --- a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml @@ -18,7 +18,7 @@ <actionGroup name="AdminCreateRole"> <arguments> <argument name="role" type="string" defaultValue=""/> - <argument name="scope" type="string" defaultValue="Custom"/> + <argument name="resource" type="string" defaultValue="All"/> </arguments> <click selector="{{AdminCreateRoleSection.create}}" stepKey="clickToAddNewRole"/> <fillField selector="{{AdminCreateRoleSection.name}}" userInput="{{role.name}}" stepKey="setRoleName"/> From 80669e3c52cd94ce60f5ee2e31eda78584bba97e Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Sat, 20 Oct 2018 18:31:29 +0300 Subject: [PATCH 0257/1158] graphQl-44: added ProductTextAttributeInput --- .../Resolver/Product/ProductTextAttribute.php | 6 ++-- .../ProductTextAttribute/FormatList.php | 13 +++++-- .../Product/ProductTextAttribute/Html.php | 2 +- .../CatalogGraphQl/etc/schema.graphqls | 34 ++++++++++++++----- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php index 7649464e2e1ca..2ff6faa0a74ee 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php @@ -39,7 +39,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function resolve( Field $field, @@ -55,8 +55,8 @@ public function resolve( /* @var $product Product */ $product = $value['model']; $fieldName = $field->getName(); - $formatIdentifier = $args['format'] ?? $this->defaultFormat; - $format = $this->formatList->create($formatIdentifier); + $formatIdentifier = $args['filter']['description']['format'] ?? $this->defaultFormat; + $format = $this->formatList->getFormatByIdentifier($formatIdentifier); $result = ['content' => $format->getContent($product, $fieldName)]; return $result; diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php index 2e2f21d643092..39f2074ed7592 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php @@ -7,8 +7,13 @@ namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\ObjectManagerInterface; +/** + * Class FormatList + * @package Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute + */ class FormatList { /** @@ -37,10 +42,12 @@ public function __construct( * @param string $formatIdentifier * @return FormatInterface */ - public function create(string $formatIdentifier) : FormatInterface + public function getFormatByIdentifier(string $formatIdentifier) : FormatInterface { - $formatClassName = 'Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\\' . ucfirst($formatIdentifier); - $formatInstance = $this->objectManager->get($formatClassName); + if (!isset($this->formats[$formatIdentifier])) { + throw new GraphQlInputException(__('Format %1 does not exist.', [$formatIdentifier])); + } + $formatInstance = $this->objectManager->get($this->formats[$formatIdentifier]); return $formatInstance; } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php index 75c29a3f78fac..830fbf28e3373 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php @@ -44,4 +44,4 @@ public function getContent( ): string { return $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); } -} \ No newline at end of file +} diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 944cae6537bb0..a7d9ab5483d46 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") - short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") + description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") + short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") @@ -433,8 +433,8 @@ type CategoryProducts @doc(description: "The category products object returned i input ProductFilterInput @doc(description: "ProductFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { name: FilterTypeInput @doc(description: "The product name. Customers use this name to identify the product.") sku: FilterTypeInput @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: FilterTypeInput @doc(description: "Detailed information about the product. The value can include simple HTML tags.") - short_description: FilterTypeInput @doc(description: "A short description of the product. Its use depends on the theme.") + description: ProductTextAttributeTypeInput @doc(description: "Detailed information about the product. The value can include simple HTML tags.") + short_description: ProductTextAttributeTypeInput @doc(description: "A short description of the product. Its use depends on the theme.") price: FilterTypeInput @doc(description: "The price of an item") special_price: FilterTypeInput @doc(description: "The discounted price of the product") special_from_date: FilterTypeInput @doc(description: "The beginning date that a product has a special price") @@ -557,9 +557,25 @@ type SortFields @doc(description: "SortFields contains a default value for sort options: [SortField] @doc(description: "Available sort fields") } -type ProductTextAttribute { - content ( - format: String @doc(description: "The format of content") -): String @doc(description: "The format of content") - @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") +type ProductTextAttribute @doc(description: "Product text attribute.") { + content: String +} + +input ProductTextAttributeTypeInput @doc(description: "FilterTypeInput specifies which action will be performed in a query ") { + format: String @doc(description: "Format of the content") + eq: String @doc(description: "Equals") + finset: [String] @doc(description: "Find in set. The value can contain a set of comma-separated values") + from: String @doc(description: "From. Must be used with 'to'") + gt: String @doc(description: "Greater than") + gteq: String @doc(description: "Greater than or equal to") + in: [String] @doc(description: "In. The value can contain a set of comma-separated values") + like: String @doc(description: "Like. The specified value can contain % (percent signs) to allow matching of 0 or more characters") + lt: String @doc(description: "Less than") + lteq: String @doc(description: "Less than or equal to") + moreq: String @doc(description: "More than or equal to") + neq: String @doc(description: "Not equal to") + notnull: String @doc(description: "Not null") + null: String @doc(description: "Is null") + to: String@doc(description: "To. Must be used with 'from'") + nin: [String] @doc(description: "Not in. The value can contain a set of comma-separated values") } From 76a7243995ce3d6ba205df8386da6c6d392b71dd Mon Sep 17 00:00:00 2001 From: Ronak Patel <ronak2ram@gmail.com> Date: Sun, 21 Oct 2018 12:45:04 +0530 Subject: [PATCH 0258/1158] Fixed - Total pages field returns null in category query --- .../CatalogGraphQl/Model/Resolver/Category/Products.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php index 557c7e08ff432..7a41f8fc94e74 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php @@ -92,7 +92,8 @@ public function resolve( 'items' => $searchResult->getProductsSearchResult(), 'page_info' => [ 'page_size' => $searchCriteria->getPageSize(), - 'current_page' => $currentPage + 'current_page' => $currentPage, + 'total_pages' => $maxPages ] ]; return $data; From c34e734c061209a766ad83d686b42ffa41378b27 Mon Sep 17 00:00:00 2001 From: Manuele Menozzi <mmenozzi@webgriffe.com> Date: Sun, 21 Oct 2018 17:20:28 +0200 Subject: [PATCH 0259/1158] Prevent MAGE_DIRS overwrite in pub/index.php --- pub/index.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pub/index.php b/pub/index.php index 457b83c529488..90b4778265447 100644 --- a/pub/index.php +++ b/pub/index.php @@ -25,12 +25,15 @@ } $params = $_SERVER; -$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = [ - DirectoryList::PUB => [DirectoryList::URL_PATH => ''], - DirectoryList::MEDIA => [DirectoryList::URL_PATH => 'media'], - DirectoryList::STATIC_VIEW => [DirectoryList::URL_PATH => 'static'], - DirectoryList::UPLOAD => [DirectoryList::URL_PATH => 'media/upload'], -]; +$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = array_replace_recursive( + $params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS], + [ + DirectoryList::PUB => [DirectoryList::URL_PATH => ''], + DirectoryList::MEDIA => [DirectoryList::URL_PATH => 'media'], + DirectoryList::STATIC_VIEW => [DirectoryList::URL_PATH => 'static'], + DirectoryList::UPLOAD => [DirectoryList::URL_PATH => 'media/upload'], + ] +); $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params); /** @var \Magento\Framework\App\Http $app */ $app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); From 4662ca91833b95662b8f7098718026153c290d05 Mon Sep 17 00:00:00 2001 From: vprohorov <vitaliy_prokharau@epam.com> Date: Mon, 22 Oct 2018 14:25:06 +0300 Subject: [PATCH 0260/1158] MAGETWO-91537: Search synonyms results missing for words including hyphen and numbers - Fixing test --- .../Magento/Catalog/Test/Repository/CatalogProductSimple.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml index 721b0ff570079..e90ca6bf7868a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml @@ -41,7 +41,7 @@ <field name="attribute_set_id" xsi:type="array"> <item name="dataset" xsi:type="string">default</item> </field> - <field name="name" xsi:type="string">Product \'!@#$%^&*()+:;\\|}{][?=-~` %isolation%</field> + <field name="name" xsi:type="string">Product \'!@#$%^&*()+:;\\|}{][?=~` %isolation%</field> <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field> <field name="is_virtual" xsi:type="string">No</field> <field name="product_has_weight" xsi:type="string">This item has weight</field> From bb7044698dce2e18fad007aa65d7e0c4a39b1e4c Mon Sep 17 00:00:00 2001 From: vprohorov <vitaliy_prokharau@epam.com> Date: Mon, 22 Oct 2018 16:43:34 +0300 Subject: [PATCH 0261/1158] MAGETWO-95825: [Magento cloud] - Images revert to default placeholder on import - Removing invalid image attributes from row --- app/code/Magento/CatalogImportExport/Model/Import/Product.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 7c56c266a64ef..f69b2def609e9 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1782,6 +1782,7 @@ protected function _saveProducts() if ($uploadedFile) { $uploadedImages[$columnImage] = $uploadedFile; } else { + unset($rowData[$column]); $this->addRowError( ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, From 93c6073eca8f6611ad3702b17861dd4aee7a9364 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Mon, 22 Oct 2018 15:55:02 +0200 Subject: [PATCH 0262/1158] Attempt to determine why GraphQl test modules are not present in the env --- dev/travis/before_script.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index c27e65d3897c7..52fd44c2826cc 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -152,6 +152,9 @@ case $TEST_SUITE in --admin-use-security-key=0 \ --admin-password="123123q" + php bin/magento module:status # DEBUG + php bin/magento setup:upgrade # DEBUG + echo "Enabling production mode" php bin/magento deploy:mode:set production From f9a7b81238135a51f964ef861e26c9ec6aa557e9 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Mon, 22 Oct 2018 16:17:31 +0200 Subject: [PATCH 0263/1158] Temporarily disable all other tests except api-fucntional --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index f5a25bc63543d..930172a9ea6e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,14 @@ env: - NODE_JS_VERSION=8 - MAGENTO_HOST_NAME="magento2.travis" matrix: - - TEST_SUITE=unit - - TEST_SUITE=static - - TEST_SUITE=js GRUNT_COMMAND=spec - - TEST_SUITE=js GRUNT_COMMAND=static - - TEST_SUITE=integration INTEGRATION_INDEX=1 - - TEST_SUITE=integration INTEGRATION_INDEX=2 - - TEST_SUITE=integration INTEGRATION_INDEX=3 - - TEST_SUITE=functional +# - TEST_SUITE=unit +# - TEST_SUITE=static +# - TEST_SUITE=js GRUNT_COMMAND=spec +# - TEST_SUITE=js GRUNT_COMMAND=static +# - TEST_SUITE=integration INTEGRATION_INDEX=1 +# - TEST_SUITE=integration INTEGRATION_INDEX=2 +# - TEST_SUITE=integration INTEGRATION_INDEX=3 +# - TEST_SUITE=functional - TEST_SUITE=api-functional matrix: exclude: From 4526732b81bd6f7dc17894b270ab1ef76360a1a0 Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov <isentiabov@magento.com> Date: Thu, 18 Oct 2018 11:30:29 +0300 Subject: [PATCH 0264/1158] MAGETWO-94052: CAPTCHA does not appear in "Log in" popup window - Added validation if response is undefined --- .../Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php | 7 ++++--- .../Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php | 2 +- .../view/frontend/web/js/view/checkout/loginCaptcha.js | 7 ++++--- .../view/frontend/web/js/view/authentication-popup.js | 1 - 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php index c67211be31659..f04e9ac8611bc 100644 --- a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php +++ b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php @@ -104,7 +104,7 @@ public function aroundExecute( if (!$captchaModel->isCorrect($captchaString)) { $this->sessionManager->setUsername($username); $captchaModel->logAttempt($username); - return $this->returnJsonError(__('Incorrect CAPTCHA')); + return $this->returnJsonError(__('Incorrect CAPTCHA'), true); } } @@ -118,11 +118,12 @@ public function aroundExecute( * Gets Json response. * * @param \Magento\Framework\Phrase $phrase + * @param bool $isCaptchaRequired * @return Json */ - private function returnJsonError(\Magento\Framework\Phrase $phrase): Json + private function returnJsonError(\Magento\Framework\Phrase $phrase, bool $isCaptchaRequired = false): Json { $resultJson = $this->resultJsonFactory->create(); - return $resultJson->setData(['errors' => true, 'message' => $phrase]); + return $resultJson->setData(['errors' => true, 'message' => $phrase, 'captcha' => $isCaptchaRequired]); } } diff --git a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php index ec2a49f3fc566..0764ea36897d1 100644 --- a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php @@ -158,7 +158,7 @@ public function testAroundExecuteIncorrectCaptcha() $this->resultJsonMock ->expects($this->once()) ->method('setData') - ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')]) + ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA'), 'captcha' => true]) ->will($this->returnSelf()); $closure = function () { diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js index e017ca6fe274c..a8efd0865bbb8 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js @@ -4,11 +4,12 @@ */ define([ + 'underscore', 'Magento_Captcha/js/view/checkout/defaultCaptcha', 'Magento_Captcha/js/model/captchaList', 'Magento_Customer/js/action/login' ], - function (defaultCaptcha, captchaList, loginAction) { + function (_, defaultCaptcha, captchaList, loginAction) { 'use strict'; return defaultCaptcha.extend({ @@ -25,11 +26,11 @@ define([ this.setCurrentCaptcha(currentCaptcha); loginAction.registerLoginCallback(function (loginData, response) { - if (!response.errors) { + if (!loginData['captcha_form_id'] || loginData['captcha_form_id'] !== self.formId) { return; } - if (!loginData['captcha_form_id'] || loginData['captcha_form_id'] !== self.formId) { + if (_.isUndefined(response) || !response.errors) { return; } diff --git a/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js b/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js index c14a59af49706..37bd3a19df638 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js +++ b/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js @@ -84,7 +84,6 @@ define([ if (formElement.validation() && formElement.validation('isValid') ) { - this.isLoading(true); loginAction(loginData); } From 97b519cafff9638d9455d9dc2e0aaca3704d805b Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Mon, 22 Oct 2018 19:19:21 +0200 Subject: [PATCH 0265/1158] Introduced cart address resolver and data provider --- .../Resolver/Address/AddressDataProvider.php | 70 +++++++++++++++ .../Model/Resolver/CartAddress.php | 87 +++++++++++++++++++ .../SetShippingMethodsOnCart.php | 6 +- .../Magento/QuoteGraphQl/etc/schema.graphqls | 22 ++--- 4 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php new file mode 100644 index 0000000000000..d401f296cb465 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\Address; + +use Magento\Framework\Api\ExtensibleDataObjectConverter; +use Magento\Quote\Api\Data\AddressInterface; +use Magento\Quote\Api\Data\CartInterface; + +/** + * Class AddressDataProvider + * + * Collect and return information about cart shipping and billing addresses + */ +class AddressDataProvider +{ + /** + * @var ExtensibleDataObjectConverter + */ + private $dataObjectConverter; + + /** + * AddressDataProvider constructor. + * + * @param ExtensibleDataObjectConverter $dataObjectConverter + */ + public function __construct( + ExtensibleDataObjectConverter $dataObjectConverter + ) { + $this->dataObjectConverter = $dataObjectConverter; + } + + /** + * Collect and return information about shipping and billing addresses + * + * @param CartInterface $cart + * @return array + */ + public function getCartAddresses(CartInterface $cart): array + { + $addressData = []; + $shippingAddress = $cart->getShippingAddress(); + $billingAddress = $cart->getBillingAddress(); + + if ($shippingAddress) { + $shippingData = $this->dataObjectConverter->toFlatArray($shippingAddress, [], AddressInterface::class); + $shippingData['address_type'] = 'SHIPPING'; + $shippingData['selected_shipping_method'] = [ + 'code' => $shippingAddress->getShippingMethod(), + 'label' => $shippingAddress->getShippingDescription(), + 'free_shipping' => $shippingAddress->getFreeShipping(), + ]; + $shippingData['items_weight'] = $shippingAddress->getWeight(); + $shippingData['customer_notes'] = $shippingAddress->getCustomerNotes(); + $addressData[] = $shippingData; + } + + if ($billingAddress) { + $billingData = $this->dataObjectConverter->toFlatArray($billingAddress, [], AddressInterface::class); + $billingData['address_type'] = 'BILLING'; + $addressData[] = $billingData; + } + + return $addressData; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php new file mode 100644 index 0000000000000..f83a112ba5ba8 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteId; +use Magento\QuoteGraphQl\Model\Resolver\Address\AddressDataProvider; + +/** + * @inheritdoc + */ +class CartAddress implements ResolverInterface +{ + /** + * @var AddressDataProvider + */ + private $addressDataProvider; + + /** + * @var CartRepositoryInterface + */ + private $cartRepository; + + /** + * @var MaskedQuoteIdToQuoteId + */ + private $maskedQuoteIdToQuoteId; + + /** + * CartAddress constructor. + * + * @param MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId + * @param CartRepositoryInterface $cartRepository + * @param AddressDataProvider $addressDataProvider + */ + public function __construct( + MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId, + CartRepositoryInterface $cartRepository, + AddressDataProvider $addressDataProvider + ) { + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->cartRepository = $cartRepository; + $this->addressDataProvider = $addressDataProvider; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($value['cart_id'])) { + // TODO: consider the possibility to pass quote model instead od quote ID + throw new LocalizedException(__('"cart_id" value should be specified')); + } + + try { + $quoteId = $this->maskedQuoteIdToQuoteId->execute($value['cart_id']); + } catch (NoSuchEntityException $exception) { + throw new GraphQlNoSuchEntityException( + __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $value['cart_id']]) + ); + } + + // TODO: should we check customer permissions here as well? + + try { + $quote = $this->cartRepository->get($quoteId); + } catch (NoSuchEntityException $exception) { + throw new GraphQlNoSuchEntityException( + __('Could not find a cart with ID "%quote_id"', ['quote_id' => $quoteId]) + ); + } + + return $this->addressDataProvider->getCartAddresses($quote); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php index c2d14668a2e70..1f35f37d9cf23 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php @@ -158,6 +158,10 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value throw new GraphQlInputException(__($exception->getMessage())); } - return 'Success!'; // TODO we should return cart here + return [ + 'cart' => [ + 'cart_id' => $maskedCartId + ] + ]; } } diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 730a54377b370..cbc56bfaea66f 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -67,7 +67,7 @@ type SetShippingAddressesOnCartOutput { } type SetShippingMethodsOnCartOutput { - cart: String #TODO: temp placeholder, should be Cart! + cart: Cart! } # If no address is provided, the system get address assigned to a quote @@ -92,28 +92,28 @@ type ApplyCouponToCartOutput { } type Cart { + cart_id: String items: [CartItemInterface] applied_coupon: AppliedCoupon - addresses: [CartAddress]! + addresses: [CartAddress]! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartAddress") } type CartAddress { - firstname: String! - lastname: String! + firstname: String + lastname: String company: String - street: [String!]! - city: String! + street: [String] + city: String region: CartAddressRegion postcode: String - country: CartAddressCountry! - telephone: String! - address_type: AdressTypeEnum! + country: CartAddressCountry + telephone: String + address_type: AdressTypeEnum selected_shipping_method: CheckoutShippingMethod - available_shipping_methods: [CheckoutShippingMethod]! + available_shipping_methods: [CheckoutShippingMethod] items_weight: Float customer_notes: String cart_items: [CartItemQuantity] - applied_coupon: AppliedCoupon } type CartItemQuantity { From 7bc9c31cdba8a4c4aca2c7fe3276688124b9b75a Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Tue, 23 Oct 2018 08:23:45 -0400 Subject: [PATCH 0266/1158] Collect totals in placeOrder when no paymentMethod provided Quote item values such as `base_original_price` are only populated during total collection. Currently in `QuoteManagement::placeOrder` if `$paymentMethod` is passed `Payment::importData` collects the quote totals to populate these values. Payment methods like Auth.net DirectPost do pass a value for `$paymentMethod` during order placement which causes order items to be converted with zero values for the `original_price` attributes. Fixes #16050 --- app/code/Magento/Quote/Model/QuoteManagement.php | 2 ++ app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 451ad08d425f5..9084ca8066301 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -349,6 +349,8 @@ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) $data = $paymentMethod->getData(); $quote->getPayment()->importData($data); + } else { + $quote->collectTotals(); } if ($quote->getCheckoutMethod() === self::METHOD_GUEST) { diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php index 107445bb18d2a..72e516e35cd6e 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php @@ -188,6 +188,7 @@ protected function setUp() 'setCustomerGroupId', 'assignCustomer', 'getPayment', + 'collectTotals' ]); $this->quoteAddressFactory = $this->createPartialMock( @@ -687,6 +688,7 @@ public function testPlaceOrderIfCustomerIsGuest() $service->expects($this->once())->method('submit')->willReturn($orderMock); $this->quoteMock->expects($this->atLeastOnce())->method('getId')->willReturn($cartId); + $this->quoteMock->expects($this->once())->method('collectTotals')->willReturnSelf(); $orderMock->expects($this->atLeastOnce())->method('getId')->willReturn($orderId); $orderMock->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($orderIncrementId); From 413120a87e73dabfe9f7bfefa989f6aa72e805fd Mon Sep 17 00:00:00 2001 From: vtymchynskyi <vtymchynskyi@magento.com> Date: Tue, 23 Oct 2018 16:48:05 +0300 Subject: [PATCH 0267/1158] MAGETWO-95539: [2.3] Moving Category generate duplicate url_rewrite when 4th level category exist and is translated - Fixed url rewrites regeneration after category moving --- .../CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php | 1 - .../Test/Unit/Model/Category/Plugin/Category/MoveTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php index fcdc21bedc5f8..f3984bf7d62ab 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Category/Move.php @@ -64,7 +64,6 @@ public function afterChangeParent( Category $newParent, $afterCategoryId ) { - $categoryStoreId = $category->getStoreId(); foreach ($category->getStoreIds() as $storeId) { $category->setStoreId($storeId); diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php index b69aabe76c35e..85e8837027151 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Category/MoveTest.php @@ -69,7 +69,7 @@ protected function setUp() ->getMock(); $this->categoryMock = $this->getMockBuilder(Category::class) ->disableOriginalConstructor() - ->setMethods(['getResource', 'setUrlPath', 'getStoreIds']) + ->setMethods(['getResource', 'setUrlPath', 'getStoreIds', 'getStoreId', 'setStoreId']) ->getMock(); $this->plugin = $this->objectManager->getObject( CategoryMovePlugin::class, From f66d26afbbe9e44afb800a6255213e11ae8fab72 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 23 Oct 2018 17:01:19 +0200 Subject: [PATCH 0268/1158] Added debug information for checking tests modules are deployed --- dev/tests/integration/framework/deployTestModules.php | 4 +++- dev/travis/before_script.sh | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/framework/deployTestModules.php b/dev/tests/integration/framework/deployTestModules.php index 4c894d80f9800..f7be2b8414d23 100644 --- a/dev/tests/integration/framework/deployTestModules.php +++ b/dev/tests/integration/framework/deployTestModules.php @@ -1,4 +1,4 @@ -<?php +x<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. @@ -38,3 +38,5 @@ foreach ($files as $file) { include $file; } + +echo "\n\n TEST MODULES WERE DEPLOYED \n\n"; // DEBUG diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index 52fd44c2826cc..c27e65d3897c7 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -152,9 +152,6 @@ case $TEST_SUITE in --admin-use-security-key=0 \ --admin-password="123123q" - php bin/magento module:status # DEBUG - php bin/magento setup:upgrade # DEBUG - echo "Enabling production mode" php bin/magento deploy:mode:set production From 2736ff910b56784ffe8513dec151d31b854dba65 Mon Sep 17 00:00:00 2001 From: pganapat <prabhuramgr28493@gmail.com> Date: Tue, 23 Oct 2018 10:11:20 -0500 Subject: [PATCH 0269/1158] MAGETWO-95213: Updating Product Status With Mass Action By Scope Updates The Default Value - Added MFTF case to cover the scenario MAGETWO-95213. Associated with Zephyr test MAGETWO-59361 --- .../ActionGroup/AdminProductActionGroup.xml | 21 +++ .../Catalog/Test/Mftf/Data/ProductData.xml | 30 ++++ .../Section/AdminProductFiltersSection.xml | 2 + .../Mftf/Section/AdminProductGridSection.xml | 1 + ...sUpdateProductStatusStoreViewScopeTest.xml | 151 ++++++++++++++++++ .../AdminFilterStoreViewActionGroup.xml | 21 +++ 6 files changed, 226 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml create mode 100644 app/code/Magento/Store/Test/Mftf/ActionGroup/AdminFilterStoreViewActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index 9f8d827b20849..f06cc816e8595 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -277,4 +277,25 @@ <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> + <!--Create a Simple Product--> + <actionGroup name="createSimpleProductAndAddToWebsite"> + <arguments> + <argument name="product"/> + <argument name="website" type="string"/> + </arguments> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToCatalogProductGrid"/> + <waitForPageLoad stepKey="waitForProductGrid"/> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> + <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> + <fillField userInput="{{product.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillProductName"/> + <fillField userInput="{{product.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillProductSKU"/> + <fillField userInput="{{product.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillProductPrice"/> + <fillField userInput="{{product.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillProductQuantity"/> + <click selector="{{ProductInWebsitesSection.sectionHeader}}" stepKey="openProductInWebsites"/> + <click selector="{{ProductInWebsitesSection.website(website)}}" stepKey="selectWebsite"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSave"/> + <waitForLoadingMaskToDisappear stepKey="waitForProductPageSave"/> + <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="seeSaveProductMessage"/> + </actionGroup> + </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 7c0cc03186c6e..494335dd56f13 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -420,4 +420,34 @@ <data key="status">1</data> <requiredEntity type="product_extension_attribute">EavStock100</requiredEntity> </entity> + <entity name="simpleProductForMassUpdate" type="product"> + <data key="sku" unique="suffix">testSku</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">massUpdateProductName</data> + <data key="keyword">massUpdateProductName</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">masstesturlkey</data> + <data key="status">1</data> + <data key="quantity">100</data> + <data key="weight">1</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + <entity name="simpleProductForMassUpdate2" type="product"> + <data key="sku" unique="suffix">testSku</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">massUpdateProductName</data> + <data key="keyword">massUpdateProductName</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">masstesturlkey</data> + <data key="status">1</data> + <data key="quantity">100</data> + <data key="weight">1</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> </entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml index 7a9de9670f216..06ff54b2a3997 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml @@ -28,5 +28,7 @@ <element name="priceOfFirstRow" type="text" selector="//tr[@data-repeat-index='0']//div[contains(., '{{var1}}')]" parameterized="true"/> <element name="AllProductsNotOfBundleType" type="text" selector="//td[5]/div[text() != 'Bundle Product']"/> <element name="attributeSetOfFirstRow" type="text" selector="//tr[@data-repeat-index='0']//div[contains(., '{{var1}}')]" parameterized="true"/> + <element name="storeViewDropDown" type="multiselect" selector="//select[@name='store_id']" timeout="30"/> + <element name="storeViewOption" type="multiselect" selector="//select[@name='store_id']/option[contains(text(),'{{var1}}')]" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml index a7e20e22f1ddc..d12233206ce41 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml @@ -28,6 +28,7 @@ <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> <element name="productGridCheckboxOnRow" type="checkbox" selector="//*[@id='container']//tr[{{row}}]/td[1]//input" parameterized="true"/> <element name="productGridNameProduct" type="input" selector="//tbody//tr//td//div[contains(., '{{var1}}')]" parameterized="true" timeout="30"/> + <element name="productGridContentsOnRow" type="checkbox" selector="//*[@id='container']//tr[{{row}}]/td" parameterized="true"/> <element name="selectRowBasedOnName" type="input" selector="//td/div[text()='{{var1}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml new file mode 100644 index 0000000000000..6d1f266f4c66b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMassUpdateProductStatusStoreViewScopeTest"> + <annotations> + <features value="Catalog"/> + <stories value="Mass update product status"/> + <title value="Admin should be able to mass update product statuses in store view scope"/> + <description value="Admin should be able to mass update product statuses in store view scope"/> + <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-59361"/> + <group value="Catalog"/> + <group value="Product Attributes"/> + </annotations> + <before> + <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> + + <!--Create Website --> + <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createAdditionalWebsite"> + <argument name="newWebsiteName" value="Second Website"/> + <argument name="websiteCode" value="second_website"/> + </actionGroup> + + <!--Create Store --> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createNewStore"> + <argument name="website" value="Second Website"/> + <argument name="storeGroupName" value="Second Store"/> + <argument name="storeGroupCode" value="second_store"/> + </actionGroup> + + <!--Create Store view --> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="amOnAdminSystemStorePage"/> + <waitForPageLoad stepKey="waitForSystemStorePage"/> + <click selector="{{AdminStoresMainActionsSection.createStoreViewButton}}" stepKey="createStoreViewButton"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <waitForElementVisible selector="//legend[contains(., 'Store View Information')]" stepKey="waitForNewStorePageToOpen"/> + <selectOption userInput="Second Store" selector="{{AdminNewStoreSection.storeGrpDropdown}}" stepKey="selectStoreGroup"/> + <fillField userInput="Second Store View" selector="{{AdminNewStoreSection.storeNameTextField}}" stepKey="fillStoreViewName"/> + <fillField userInput="second_store_view" selector="{{AdminNewStoreSection.storeCodeTextField}}" stepKey="fillStoreViewCode"/> + <selectOption selector="{{AdminNewStoreSection.statusDropdown}}" userInput="1" stepKey="enableStoreViewStatus"/> + <click selector="{{AdminNewStoreViewActionsSection.saveButton}}" stepKey="clickSaveStoreView" /> + <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitForModal" /> + <see selector="{{AdminConfirmationModalSection.title}}" userInput="Warning message" stepKey="seeWarning" /> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="dismissModal" /> + <waitForPageLoad stepKey="waitForPageLoad2" time="180" /> + <waitForElementVisible selector="{{AdminStoresGridSection.storeFilterTextField}}" time="150" stepKey="waitForPageReolad"/> + <see userInput="You saved the store view." stepKey="seeSavedMessage" /> + + <!--Create a Simple Product 1 --> + <actionGroup ref="createSimpleProductAndAddToWebsite" stepKey="createSimpleProduct1"> + <argument name="product" value="simpleProductForMassUpdate"/> + <argument name="website" value="Second Website"/> + </actionGroup> + + <!--Create a Simple Product 2 --> + <actionGroup ref="createSimpleProductAndAddToWebsite" stepKey="createSimpleProduct2"> + <argument name="product" value="simpleProductForMassUpdate2"/> + <argument name="website" value="Second Website"/> + </actionGroup> + </before> + <after> + <!--Delete website --> + <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteSecondWebsite"> + <argument name="websiteName" value="Second Website"/> + </actionGroup> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + + <!--Delete Products --> + <actionGroup ref="DeleteProductActionGroup" stepKey="deleteProduct1"> + <argument name="productName" value="simpleProductForMassUpdate.name"/> + </actionGroup> + <actionGroup ref="DeleteProductActionGroup" stepKey="deleteProduct2"> + <argument name="productName" value="simpleProductForMassUpdate2.name"/> + </actionGroup> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Search and select products --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="searchProductGridByKeyword2" stepKey="searchByKeyword"> + <argument name="keyword" value="{{simpleProductForMassUpdate.keyword}}"/> + </actionGroup> + <actionGroup ref="sortProductsByIdDescending" stepKey="sortProductsByIdDescending"/> + + <!-- Filter to Second Store View --> + <actionGroup ref="AdminFilterStoreViewActionGroup" stepKey="filterStoreView" > + <argument name="customStore" value="'Second Store View'" /> + </actionGroup> + + <!-- Select Product 2 --> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('2')}}" stepKey="clickCheckbox2"/> + + <!-- Mass update attributes --> + <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickDropdown"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Change status')}}" stepKey="clickOption"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Disable')}}" stepKey="clickDisabled"/> + <waitForPageLoad stepKey="waitForBulkUpdatePage"/> + + <!-- Verify Product Statuses --> + <see selector="{{AdminProductGridSection.productGridContentsOnRow('1')}}" userInput="Enabled" stepKey="checkIfProduct1IsEnabled"/> + <see selector="{{AdminProductGridSection.productGridContentsOnRow('2')}}" userInput="Disabled" stepKey="checkIfProduct2IsDisabled"/> + + <!-- Filter to Default Store View --> + <actionGroup ref="AdminFilterStoreViewActionGroup" stepKey="filterDefaultStoreView"> + <argument name="customStore" value="'Default'" /> + </actionGroup> + + <!-- Verify Product Statuses --> + <see selector="{{AdminProductGridSection.productGridContentsOnRow('1')}}" userInput="Enabled" stepKey="checkIfDefaultViewProduct1IsEnabled"/> + <see selector="{{AdminProductGridSection.productGridContentsOnRow('2')}}" userInput="Enabled" stepKey="checkIfDefaultViewProduct2IsEnabled"/> + + <!-- Assert on storefront default view --> + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroupDefault"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameAndDescriptionActionGroup" stepKey="searchByNameDefault"> + <argument name="name" value="{{simpleProductForMassUpdate.keyword}}"/> + <argument name="description" value=""/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResultDefault"/> + <see userInput="2 items" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="seeInDefault"/> + + <!-- Enable the product in Default store view --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex2"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('1')}}" stepKey="clickCheckboxDefaultStoreView"/> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('2')}}" stepKey="clickCheckboxDefaultStoreView2"/> + + <!-- Mass update attributes --> + <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickDropdownDefaultStoreView"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Change status')}}" stepKey="clickOptionDefaultStoreView"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Disable')}}" stepKey="clickDisabledDefaultStoreView"/> + <waitForPageLoad stepKey="waitForBulkUpdatePageDefaultStoreView"/> + <see selector="{{AdminProductGridSection.productGridContentsOnRow('1')}}" userInput="Disabled" stepKey="checkIfProduct2IsDisabledDefaultStoreView"/> + + <!-- Assert on storefront default view --> + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroupDefault2"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameAndDescriptionActionGroup" stepKey="searchByNameDefault2"> + <argument name="name" value="{{simpleProductForMassUpdate.name}}"/> + <argument name="description" value=""/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResultDefault2"/> + <see userInput="We can't find any items matching these search criteria." selector="{{StorefrontCatalogSearchAdvancedResultMainSection.message}}" stepKey="seeInDefault2"/> + </test> +</tests> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminFilterStoreViewActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminFilterStoreViewActionGroup.xml new file mode 100644 index 0000000000000..e4cb26ea6ff7a --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminFilterStoreViewActionGroup.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- Test XML Example --> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFilterStoreViewActionGroup"> + <arguments> + <argument name="StoreGroup" defaultValue="_defaultStoreGroup"/> + <argument name="customStore" defaultValue="customStore.name"/> + </arguments> + <click selector="{{AdminProductFiltersSection.filter}}" stepKey="ClickOnFilter"/> + <click selector="{{AdminProductFiltersSection.storeViewDropDown}}" stepKey="ClickOnStoreViewDropDown"/> + <click selector="{{AdminProductFiltersSection.storeViewOption(customStore)}}" stepKey="ClickOnStoreViewOption"/> + <click selector="{{AdminProductFiltersSection.applyFilters}}" stepKey="ClickOnApplyFilters"/> + </actionGroup> +</actionGroups> From 66329bbd41a6aac1d454c73c4e826e547dc81a02 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 23 Oct 2018 17:43:50 +0200 Subject: [PATCH 0270/1158] More details in debug information about deployed modules --- dev/tests/integration/framework/deployTestModules.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/integration/framework/deployTestModules.php b/dev/tests/integration/framework/deployTestModules.php index f7be2b8414d23..6e57d748a55eb 100644 --- a/dev/tests/integration/framework/deployTestModules.php +++ b/dev/tests/integration/framework/deployTestModules.php @@ -25,6 +25,7 @@ mkdir($targetDir, 0755, true); } copy($source, $destination); + echo "\n\nDestination $destination\n\n"; // DEBUG } } unset($iterator, $file); @@ -38,5 +39,3 @@ foreach ($files as $file) { include $file; } - -echo "\n\n TEST MODULES WERE DEPLOYED \n\n"; // DEBUG From 29cb28b41987ae4199fbc8ac14c3640d2224ec23 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 23 Oct 2018 17:58:54 +0200 Subject: [PATCH 0271/1158] Remove debug info --- dev/tests/integration/framework/deployTestModules.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/integration/framework/deployTestModules.php b/dev/tests/integration/framework/deployTestModules.php index 6e57d748a55eb..f4fb881d3ed70 100644 --- a/dev/tests/integration/framework/deployTestModules.php +++ b/dev/tests/integration/framework/deployTestModules.php @@ -25,7 +25,6 @@ mkdir($targetDir, 0755, true); } copy($source, $destination); - echo "\n\nDestination $destination\n\n"; // DEBUG } } unset($iterator, $file); From 4fdc63807fff721244e7ccff31064b634904075b Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 23 Oct 2018 18:04:52 +0200 Subject: [PATCH 0272/1158] removed accidentally added char --- dev/tests/integration/framework/deployTestModules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/framework/deployTestModules.php b/dev/tests/integration/framework/deployTestModules.php index f4fb881d3ed70..4c894d80f9800 100644 --- a/dev/tests/integration/framework/deployTestModules.php +++ b/dev/tests/integration/framework/deployTestModules.php @@ -1,4 +1,4 @@ -x<?php +<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. From a18a08792acf1d251c491894d0889783d3b73c02 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Tue, 23 Oct 2018 22:48:01 +0300 Subject: [PATCH 0273/1158] graphQl-44: added html content resolver --- .../Resolver/Product/ProductTextAttribute.php | 64 ------------------- .../ProductTextAttribute/FormatInterface.php | 23 ------- .../ProductTextAttribute/FormatList.php | 54 ---------------- .../Product/ProductTextAttribute/Html.php | 47 -------------- .../ProductTextAttribute/HtmlContent.php | 56 ++++++++++++++++ .../CatalogGraphQl/etc/schema.graphqls | 29 ++------- 6 files changed, 61 insertions(+), 212 deletions(-) delete mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php delete mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php delete mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php delete mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php deleted file mode 100644 index 2ff6faa0a74ee..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogGraphQl\Model\Resolver\Product; - -use Magento\Catalog\Model\Product; -use Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\FormatList; -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; - -/** - * Resolve rendered content for attributes where HTML content is allowed - */ -class ProductTextAttribute implements ResolverInterface -{ - /** - * @var FormatList - */ - private $formatList; - - /** - * @var string - */ - private $defaultFormat = 'html'; - - /** - * @param FormatList $formatList - */ - public function __construct( - FormatList $formatList - ) { - $this->formatList = $formatList; - } - - /** - * @inheritdoc - */ - public function resolve( - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!isset($value['model'])) { - throw new GraphQlInputException(__('"model" value should be specified')); - } - - /* @var $product Product */ - $product = $value['model']; - $fieldName = $field->getName(); - $formatIdentifier = $args['filter']['description']['format'] ?? $this->defaultFormat; - $format = $this->formatList->getFormatByIdentifier($formatIdentifier); - $result = ['content' => $format->getContent($product, $fieldName)]; - - return $result; - } -} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php deleted file mode 100644 index 2cf702bf18466..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; - -use Magento\Catalog\Model\Product as ModelProduct; - -interface FormatInterface -{ - /** - * @param ModelProduct $product - * @param string $fieldName - * @return string - */ - public function getContent( - ModelProduct $product, - string $fieldName - ): string; -} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php deleted file mode 100644 index 39f2074ed7592..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/FormatList.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; - -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\ObjectManagerInterface; - -/** - * Class FormatList - * @package Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute - */ -class FormatList -{ - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $formats; - - /** - * @param ObjectManagerInterface $objectManager - * @param array $formats - */ - public function __construct( - ObjectManagerInterface $objectManager, - array $formats - ) { - $this->objectManager = $objectManager; - $this->formats = $formats; - } - - /** - * @param string $formatIdentifier - * @return FormatInterface - */ - public function getFormatByIdentifier(string $formatIdentifier) : FormatInterface - { - if (!isset($this->formats[$formatIdentifier])) { - throw new GraphQlInputException(__('Format %1 does not exist.', [$formatIdentifier])); - } - $formatInstance = $this->objectManager->get($this->formats[$formatIdentifier]); - - return $formatInstance; - } -} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php deleted file mode 100644 index 830fbf28e3373..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/Html.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; - -use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; -use Magento\Catalog\Helper\Output as OutputHelper; -use Magento\Catalog\Model\Product as ModelProduct; - -class Html implements FormatInterface -{ - /** - * @var ValueFactory - */ - private $valueFactory; - - /** - * @var OutputHelper - */ - private $outputHelper; - - /** - * @param ValueFactory $valueFactory - * @param OutputHelper $outputHelper - */ - public function __construct( - ValueFactory $valueFactory, - OutputHelper $outputHelper - ) { - $this->valueFactory = $valueFactory; - $this->outputHelper = $outputHelper; - } - - /** - * @inheritdoc - */ - public function getContent( - ModelProduct $product, - string $fieldName - ): string { - return $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); - } -} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php new file mode 100644 index 0000000000000..c0b67889ecd74 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; + +use Magento\Catalog\Model\Product; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Catalog\Helper\Output as OutputHelper; + +/** + * HTML content of Product Text Attribute + */ +class HtmlContent implements ResolverInterface +{ + /** + * @var OutputHelper + */ + private $outputHelper; + + /** + * @param OutputHelper $outputHelper + */ + public function __construct( + OutputHelper $outputHelper + ) { + $this->outputHelper = $outputHelper; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ): array { + if (!isset($value['model'])) { + return []; + } + + /* @var $product Product */ + $product = $value['model']; + $fieldName = $field->getName(); + $renderedValue = $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); + + return $renderedValue; + } +} diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index a7d9ab5483d46..3ffdc85a40d68 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") - short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") + description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") + short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") @@ -433,8 +433,8 @@ type CategoryProducts @doc(description: "The category products object returned i input ProductFilterInput @doc(description: "ProductFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { name: FilterTypeInput @doc(description: "The product name. Customers use this name to identify the product.") sku: FilterTypeInput @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ProductTextAttributeTypeInput @doc(description: "Detailed information about the product. The value can include simple HTML tags.") - short_description: ProductTextAttributeTypeInput @doc(description: "A short description of the product. Its use depends on the theme.") + description: FilterTypeInput @doc(description: "Detailed information about the product. The value can include simple HTML tags.") + short_description: FilterTypeInput @doc(description: "A short description of the product. Its use depends on the theme.") price: FilterTypeInput @doc(description: "The price of an item") special_price: FilterTypeInput @doc(description: "The discounted price of the product") special_from_date: FilterTypeInput @doc(description: "The beginning date that a product has a special price") @@ -558,24 +558,5 @@ type SortFields @doc(description: "SortFields contains a default value for sort } type ProductTextAttribute @doc(description: "Product text attribute.") { - content: String -} - -input ProductTextAttributeTypeInput @doc(description: "FilterTypeInput specifies which action will be performed in a query ") { - format: String @doc(description: "Format of the content") - eq: String @doc(description: "Equals") - finset: [String] @doc(description: "Find in set. The value can contain a set of comma-separated values") - from: String @doc(description: "From. Must be used with 'to'") - gt: String @doc(description: "Greater than") - gteq: String @doc(description: "Greater than or equal to") - in: [String] @doc(description: "In. The value can contain a set of comma-separated values") - like: String @doc(description: "Like. The specified value can contain % (percent signs) to allow matching of 0 or more characters") - lt: String @doc(description: "Less than") - lteq: String @doc(description: "Less than or equal to") - moreq: String @doc(description: "More than or equal to") - neq: String @doc(description: "Not equal to") - notnull: String @doc(description: "Not null") - null: String @doc(description: "Is null") - to: String@doc(description: "To. Must be used with 'from'") - nin: [String] @doc(description: "Not in. The value can contain a set of comma-separated values") + html: String @doc(description: "Attribute HTML content") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute\\HtmlContent") } From 6e1710aec76825c8fc03e1e159f518dfba8d18e4 Mon Sep 17 00:00:00 2001 From: pganapat <prabhuramgr28493@gmail.com> Date: Tue, 23 Oct 2018 17:29:09 -0500 Subject: [PATCH 0274/1158] MAGETWO-95213: Updating Product Status With Mass Action By Scope Updates The Default Value - Review comments fix. Using action group for logout. --- .../Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml index 6d1f266f4c66b..e9b54e3f1a3dc 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductStatusStoreViewScopeTest.xml @@ -79,7 +79,7 @@ <actionGroup ref="DeleteProductActionGroup" stepKey="deleteProduct2"> <argument name="productName" value="simpleProductForMassUpdate2.name"/> </actionGroup> - <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <actionGroup ref="logout" stepKey="amOnLogoutPage"/> </after> <!-- Search and select products --> From 53b5b4902f08c20d7b5ceea85fea8fd8823ae055 Mon Sep 17 00:00:00 2001 From: godvsdeity <alex.simplecoding@gmail.com> Date: Wed, 24 Oct 2018 02:00:10 +0300 Subject: [PATCH 0275/1158] performance improvements Get rid of unnecessary reviews queries on product listing: "select review_entity_summary.* from review_entity_summary where (review_entity_summary.entity_pk_value = ?) and (store_id = ?)" This query was executed for each product on listing which didn't have a review summary(@see: Magento\Review\Block\Product\ReviewRenderer::getReviewsSummaryHtml) --- app/code/Magento/Review/Model/Review.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/Review/Model/Review.php b/app/code/Magento/Review/Model/Review.php index c00af3fc61407..e689d4ed460ac 100644 --- a/app/code/Magento/Review/Model/Review.php +++ b/app/code/Magento/Review/Model/Review.php @@ -5,6 +5,7 @@ */ namespace Magento\Review\Model; +use Magento\Framework\DataObject; use Magento\Catalog\Model\Product; use Magento\Framework\DataObject\IdentityInterface; use Magento\Review\Model\ResourceModel\Review\Product\Collection as ProductCollection; @@ -327,6 +328,9 @@ public function appendSummary($collection) $item->setRatingSummary($summary); } } + if (!$item->getRatingSummary()) { + $item->setRatingSummary(new DataObject()); + } } return $this; From d9de494dcfd714101117a6619895805aeec6f8e8 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Wed, 24 Oct 2018 01:24:02 -0700 Subject: [PATCH 0276/1158] MAGETWO-95520: Verify that Catalog Price Rule and Customer Group Membership are persisted under long-term cookie --- .../CatalogPriceRuleActionGroup.xml | 19 +++++ ...hipArePersistedUnderLongTermCookieTest.xml | 85 +++++++++++++++++++ .../Section/StorefrontPanelHeaderSection.xml | 1 + .../Test/Mftf/Data/PersistentData.xml | 14 +++ .../Mftf/Metadata/persistent_config-meta.xml | 3 + 5 files changed, 122 insertions(+) create mode 100644 app/code/Magento/CatalogRule/Test/Mftf/Test/CatalogPriceRuleAndCustomerGroupMembershipArePersistedUnderLongTermCookieTest.xml diff --git a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml index cfd41f2ab970c..fe4042e8a2e9f 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml @@ -58,4 +58,23 @@ <fillField selector="{{AdminNewCatalogPriceRuleConditions.targetInput('1', '1')}}" userInput="{{productSku}}" after="clickEllipsis" stepKey="fillProductSku"/> <click selector="{{AdminNewCatalogPriceRuleConditions.applyButton('1', '1')}}" after="fillProductSku" stepKey="clickApply"/> </actionGroup> + + <!--Add Catalog Rule Condition With Category--> + <actionGroup name="newCatalogPriceRuleByUIWithConditionIsCategory" extends="newCatalogPriceRuleByUI"> + <arguments> + <argument name="categoryId"/> + </arguments> + <click selector="{{AdminNewCatalogPriceRule.conditionsTab}}" after="discardSubsequentRules" stepKey="openConditionsTab"/> + <waitForPageLoad after="openConditionsTab" stepKey="waitForConditionTabOpened"/> + <click selector="{{AdminNewCatalogPriceRuleConditions.newCondition}}" after="waitForConditionTabOpened" stepKey="addNewCondition"/> + <selectOption selector="{{AdminNewCatalogPriceRuleConditions.conditionSelect('1')}}" userInput="Magento\CatalogRule\Model\Rule\Condition\Product|category_ids" after="addNewCondition" stepKey="selectTypeCondition"/> + <waitForPageLoad after="selectTypeCondition" stepKey="waitForConditionChosed"/> + <click selector="{{AdminNewCatalogPriceRuleConditions.targetEllipsis('1')}}" after="waitForConditionChosed" stepKey="clickEllipsis"/> + <fillField selector="{{AdminNewCatalogPriceRuleConditions.targetInput('1', '1')}}" userInput="{{categoryId}}" after="clickEllipsis" stepKey="fillCategoryId"/> + <click selector="{{AdminNewCatalogPriceRuleConditions.applyButton('1', '1')}}" after="fillCategoryId" stepKey="clickApply"/> + </actionGroup> + + <actionGroup name="selectGeneralCustomerGroupActionGroup"> + <selectOption selector="{{AdminNewCatalogPriceRule.customerGroups}}" userInput="General" stepKey="selectCustomerGroup"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/CatalogPriceRuleAndCustomerGroupMembershipArePersistedUnderLongTermCookieTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/CatalogPriceRuleAndCustomerGroupMembershipArePersistedUnderLongTermCookieTest.xml new file mode 100644 index 0000000000000..2e09ee7134733 --- /dev/null +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/CatalogPriceRuleAndCustomerGroupMembershipArePersistedUnderLongTermCookieTest.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CatalogPriceRuleAndCustomerGroupMembershipArePersistedUnderLongTermCookieTest"> + <annotations> + <features value="Persistent"/> + <stories value="Check the price"/> + <title value="Verify that Catalog Price Rule and Customer Group Membership are persisted under long-term cookie"/> + <description value="Verify that Catalog Price Rule and Customer Group Membership are persisted under long-term cookie"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-69455"/> + <group value="persistent"/> + </annotations> + <before> + <createData entity="PersistentConfigEnabled" stepKey="enablePersistent"/> + <createData entity="PersistentLogoutClearDisable" stepKey="persistentLogoutClearDisable"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + <field key="price">50</field> + </createData> + <createData entity="Simple_US_Customer" stepKey="createCustomer"> + <field key="group_id">1</field> + </createData> + + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <!--Create Catalog Rule--> + <actionGroup ref="newCatalogPriceRuleByUIWithConditionIsCategory" stepKey="createCatalogPriceRule"> + <argument name="catalogRule" value="_defaultCatalogRule"/> + <argument name="categoryId" value="$$createCategory.id$$"/> + </actionGroup> + <actionGroup ref="selectGeneralCustomerGroupActionGroup" stepKey="selectCustomerGroup"/> + <click selector="{{AdminNewCatalogPriceRule.saveAndApply}}" stepKey="clickSaveAndApplyRules"/> + <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule." stepKey="assertSuccess"/> + <magentoCLI command="indexer:reindex" stepKey="reindex"/> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + </before> + <after> + <!-- Delete the rule --> + <amOnPage url="{{CatalogRulePage.url}}" stepKey="goToCatalogPriceRulePage"/> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deletePriceRule"> + <argument name="name" value="{{_defaultCatalogRule.name}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.catalogRuleIdentifierSearch}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + <createData entity="PersistentConfigDefault" stepKey="setDefaultPersistentState"/> + <createData entity="PersistentLogoutClearEnabled" stepKey="persistentLogoutClearEnabled"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + </after> + + <!--Go to category and check price--> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onStorefrontCategoryPage"/> + <see selector="{{StorefrontCategoryProductSection.ProductPriceByNumber('1')}}" userInput="$$createProduct.price$$" stepKey="checkPriceSimpleProduct"/> + + <!--Login to storfront from customer and check price--> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="logInFromCustomer"> + <argument name="Customer" value="$$createCustomer$$"/> + </actionGroup> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onStorefrontCategoryPage2"/> + <see userInput="Welcome, $$createCustomer.firstname$$ $$createCustomer.lastname$$!" selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeCheckWelcome"/> + <see selector="{{StorefrontCategoryProductSection.ProductSpecialPriceByNumber('1')}}" userInput="45.00" stepKey="checkPriceSimpleProduct2"/> + + <!--Click *Sign Out* and check the price of the Simple Product--> + <actionGroup ref="StorefrontSignOutActionGroup" stepKey="storefrontSignOut"/> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onStorefrontCategoryPage3"/> + <see userInput="Welcome, $$createCustomer.firstname$$ $$createCustomer.lastname$$!" selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeCheckWelcome2"/> + <seeElement selector="{{StorefrontPanelHeaderSection.notYouLink}}" stepKey="checkLinkNotYoy"/> + <see selector="{{StorefrontCategoryProductSection.ProductSpecialPriceByNumber('1')}}" userInput="45.00" stepKey="checkPriceSimpleProduct3"/> + + <!--Click the *Not you?* link and check the price for Simple Product--> + <click selector="{{StorefrontPanelHeaderSection.notYouLink}}" stepKey="clickNext"/> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onStorefrontCategoryPage4"/> + <see userInput="Default welcome msg!" selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeCheckWelcome3"/> + <see selector="{{StorefrontCategoryProductSection.ProductPriceByNumber('1')}}" userInput="$$createProduct.price$$" stepKey="checkPriceSimpleProduct4"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontPanelHeaderSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontPanelHeaderSection.xml index 06b82db767ab5..a0c83f5bc491b 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontPanelHeaderSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontPanelHeaderSection.xml @@ -11,5 +11,6 @@ <section name="StorefrontPanelHeaderSection"> <element name="WelcomeMessage" type="text" selector=".greet.welcome span"/> <element name="createAnAccountLink" type="select" selector=".panel.header li:nth-child(3)" timeout="30"/> + <element name="notYouLink" type="button" selector=".greet.welcome span a"/> </section> </sections> diff --git a/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml b/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml index f4e2fa198e7ff..3d42ae6da81a5 100644 --- a/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml +++ b/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml @@ -20,4 +20,18 @@ <entity name="persistentEnabledState" type="persistent_options_enabled"> <data key="value">1</data> </entity> + + <entity name="PersistentLogoutClearEnabled" type="persistent_config_state"> + <requiredEntity type="persistent_options_logout_clear">persistentEnabledLogoutClear</requiredEntity> + </entity> + <entity name="persistentEnabledLogoutClear" type="logout_clear"> + <data key="value">1</data> + </entity> + + <entity name="PersistentLogoutClearDisable" type="persistent_config_state"> + <requiredEntity type="persistent_options_logout_clear">persistentDisableLogoutClear</requiredEntity> + </entity> + <entity name="persistentDisableLogoutClear" type="logout_clear"> + <data key="value">0</data> + </entity> </entities> diff --git a/app/code/Magento/Persistent/Test/Mftf/Metadata/persistent_config-meta.xml b/app/code/Magento/Persistent/Test/Mftf/Metadata/persistent_config-meta.xml index d165ca5f929b0..7f0e12f8bef93 100644 --- a/app/code/Magento/Persistent/Test/Mftf/Metadata/persistent_config-meta.xml +++ b/app/code/Magento/Persistent/Test/Mftf/Metadata/persistent_config-meta.xml @@ -14,6 +14,9 @@ <object key="enabled" dataType="persistent_options_enabled"> <field key="value">string</field> </object> + <object key="logout_clear" dataType="persistent_options_logout_clear"> + <field key="value">string</field> + </object> </object> </object> </object> From 308ac7e212fb2e60418c2b3b8b252fcfa3dc1911 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 24 Oct 2018 11:50:27 +0300 Subject: [PATCH 0277/1158] MAGETWO-95853: Can't flush Images cache in admin --- .../Framework/Filesystem/Directory/Write.php | 46 ++++++++++++++++++- .../Framework/Filesystem/Driver/File.php | 14 +++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php index 78732d73456f7..74314b747cf42 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php @@ -175,6 +175,7 @@ public function createSymlink($path, $destination, WriteInterface $targetDirecto */ public function delete($path = null) { + $exceptionMessages = []; $this->validatePath($path); if (!$this->isExist($path)) { return true; @@ -183,11 +184,54 @@ public function delete($path = null) if ($this->driver->isFile($absolutePath)) { $this->driver->deleteFile($absolutePath); } else { - $this->driver->deleteDirectory($absolutePath); + try { + $this->deleteFilesRecursively($absolutePath); + $this->driver->deleteDirectory($absolutePath); + } catch (FileSystemException $e) { + $exceptionMessages[] = $e->getMessage(); + } + } + if (!empty($exceptionMessages)) { + throw new FileSystemException( + new \Magento\Framework\Phrase( + \implode(' ', $exceptionMessages) + ) + ); } return true; } + /** + * Delete files recursively + * + * Implemented in order to delete as much files as possible and collect all exceptions + * + * @param string $path + * @return void + * @throws FileSystemException + */ + private function deleteFilesRecursively(string $path) + { + $exceptionMessages = []; + $entitiesList = $this->driver->readDirectoryRecursively($path); + foreach ($entitiesList as $entityPath) { + if (!$this->driver->isDirectory($entityPath)) { + try { + $this->driver->deleteFile($entityPath); + } catch (FileSystemException $e) { + $exceptionMessages[] = $e->getMessage(); + } + } + } + if (!empty($exceptionMessages)) { + throw new FileSystemException( + new \Magento\Framework\Phrase( + \implode(' ', $exceptionMessages) + ) + ); + } + } + /** * Change permissions of given path * diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index b54b02bd6de98..e8d51f52ff153 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -399,16 +399,28 @@ public function deleteFile($path) */ public function deleteDirectory($path) { + $exceptionMessages = []; $flags = \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS; $iterator = new \FilesystemIterator($path, $flags); /** @var \FilesystemIterator $entity */ foreach ($iterator as $entity) { if ($entity->isDir()) { - $this->deleteDirectory($entity->getPathname()); + try { + $this->deleteDirectory($entity->getPathname()); + } catch (FileSystemException $exception) { + $exceptionMessages[] = $exception->getMessage(); + } } else { $this->deleteFile($entity->getPathname()); } } + if (!empty($exceptionMessages)) { + throw new FileSystemException( + new \Magento\Framework\Phrase( + \implode(' ', $exceptionMessages) + ) + ); + } $result = @rmdir($this->getScheme() . $path); if (!$result) { throw new FileSystemException( From a14244e86c129f1296e5f5b0b2a0fac86e5fb526 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 24 Oct 2018 11:51:40 +0300 Subject: [PATCH 0278/1158] MAGETWO-95853: Can't flush Images cache in admin --- lib/internal/Magento/Framework/Filesystem/Directory/Write.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php index 74314b747cf42..cb8f6dd0b88e0 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php @@ -215,7 +215,7 @@ private function deleteFilesRecursively(string $path) $exceptionMessages = []; $entitiesList = $this->driver->readDirectoryRecursively($path); foreach ($entitiesList as $entityPath) { - if (!$this->driver->isDirectory($entityPath)) { + if ($this->driver->isFile($entityPath)) { try { $this->driver->deleteFile($entityPath); } catch (FileSystemException $e) { From 7e74d4ee5ee682926044e4c8f153437c768e62d8 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 24 Oct 2018 12:55:47 +0300 Subject: [PATCH 0279/1158] MAGETWO-95853: Can't flush Images cache in admin --- .../Magento/Framework/Filesystem/Directory/Write.php | 5 ++++- lib/internal/Magento/Framework/Filesystem/Driver/File.php | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php index cb8f6dd0b88e0..88c03f7869581 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php @@ -9,6 +9,9 @@ use Magento\Framework\Exception\FileSystemException; use Magento\Framework\Exception\ValidatorException; +/** + * Write Interface implementation + */ class Write extends Read implements WriteInterface { /** @@ -289,7 +292,7 @@ public function touch($path, $modificationTime = null) /** * Check if given path is writable * - * @param null $path + * @param string|null $path * @return bool * @throws \Magento\Framework\Exception\FileSystemException * @throws ValidatorException diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index e8d51f52ff153..395144ca6ee7d 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -14,6 +14,7 @@ /** * Class File + * * @package Magento\Framework\Filesystem\Driver * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ @@ -855,6 +856,8 @@ public function fileUnlock($resource) } /** + * Retrieves absolute path + * * @param string $basePath * @param string $path * @param string|null $scheme From ea180c8940a7e5da139feee9770e943cefdb96b3 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 24 Oct 2018 13:04:23 +0300 Subject: [PATCH 0280/1158] MAGETWO-95853: Can't flush Images cache in admin --- lib/internal/Magento/Framework/Filesystem/Driver/File.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index 395144ca6ee7d..4ba8f566f3f10 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -895,6 +895,7 @@ public function getRelativePath($basePath, $path = null) /** * Fixes path separator + * * Utility method. * * @param string $path From 5e8ae07871b82b7d36983f16c5296110e6a9bc9d Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu <dzmitry_tabusheu@epam.com> Date: Wed, 24 Oct 2018 14:07:54 +0300 Subject: [PATCH 0281/1158] MAGETWO-95805: User agent exception not setting the correct templates for product pages - Fixed template detection in 'ProductViewCounter' block --- .../Product/Listing/Collector/ImageTest.php | 8 +++++++- .../Product/Listing/Collector/Image.php | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php index 12bc9acfa4c51..009cd690d4cd4 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php @@ -15,6 +15,7 @@ use Magento\Catalog\Helper\ImageFactory; use Magento\Catalog\Api\Data\ProductRender\ImageInterface; use Magento\Catalog\Helper\Image as ImageHelper; +use Magento\Framework\View\DesignLoader; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -33,6 +34,9 @@ class ImageTest extends \PHPUnit\Framework\TestCase /** @var DesignInterface | \PHPUnit_Framework_MockObject_MockObject */ private $design; + /** @var DesignLoader | \PHPUnit_Framework_MockObject_MockObject*/ + private $designLoader; + /** @var Image */ private $model; @@ -60,13 +64,15 @@ public function setUp() ->getMock(); $this->storeManager = $this->createMock(StoreManagerInterface::class); $this->design = $this->createMock(DesignInterface::class); + $this->designLoader = $this->createMock(DesignLoader::class); $this->model = new Image( $this->imageFactory, $this->state, $this->storeManager, $this->design, $this->imageInterfaceFactory, - $this->imageCodes + $this->imageCodes, + $this->designLoader ); } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php index 216bc16968fcb..524927ac1c4b4 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php @@ -17,12 +17,14 @@ use Magento\Framework\View\DesignInterface; use Magento\Store\Model\StoreManager; use Magento\Store\Model\StoreManagerInterface; +use Magento\Framework\View\DesignLoader; /** * Collect enough information about image rendering on front * If you want to add new image, that should render on front you need * to configure this class in di.xml * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Image implements ProductRenderCollectorInterface { @@ -51,6 +53,7 @@ class Image implements ProductRenderCollectorInterface /** * @var DesignInterface + * @deprecated 2.3.0 DesignLoader is used for design theme loading */ private $design; @@ -59,6 +62,11 @@ class Image implements ProductRenderCollectorInterface */ private $imageRenderInfoFactory; + /** + * @var DesignLoader + */ + private $designLoader; + /** * Image constructor. * @param ImageFactory $imageFactory @@ -67,6 +75,7 @@ class Image implements ProductRenderCollectorInterface * @param DesignInterface $design * @param ImageInterfaceFactory $imageRenderInfoFactory * @param array $imageCodes + * @param DesignLoader $designLoader */ public function __construct( ImageFactory $imageFactory, @@ -74,7 +83,8 @@ public function __construct( StoreManagerInterface $storeManager, DesignInterface $design, ImageInterfaceFactory $imageRenderInfoFactory, - array $imageCodes = [] + array $imageCodes = [], + DesignLoader $designLoader = null ) { $this->imageFactory = $imageFactory; $this->imageCodes = $imageCodes; @@ -82,6 +92,8 @@ public function __construct( $this->storeManager = $storeManager; $this->design = $design; $this->imageRenderInfoFactory = $imageRenderInfoFactory; + $this->designLoader = $designLoader ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(DesignLoader::class); } /** @@ -124,6 +136,8 @@ public function collect(ProductInterface $product, ProductRenderInterface $produ } /** + * Callback for emulating image creation + * * Callback in which we emulate initialize default design theme, depends on current store, be settings store id * from render info * @@ -136,7 +150,7 @@ public function collect(ProductInterface $product, ProductRenderInterface $produ public function emulateImageCreating(ProductInterface $product, $imageCode, $storeId, ImageInterface $image) { $this->storeManager->setCurrentStore($storeId); - $this->design->setDefaultDesignTheme(); + $this->designLoader->load(); $imageHelper = $this->imageFactory->create(); $imageHelper->init($product, $imageCode); From 0a4dc35bb14a28634a7b58e9fe12e68df7e86ea7 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Wed, 24 Oct 2018 14:21:40 +0300 Subject: [PATCH 0282/1158] graphQl-44: added ProductTextAttribute and fixed api functional test --- .../Resolver/Product/ProductTextAttribute.php | 33 +++++++++++++++++ .../ProductTextAttribute/HtmlContent.php | 10 ++++-- .../CatalogGraphQl/etc/schema.graphqls | 4 +-- .../GraphQl/Catalog/ProductViewTest.php | 36 ++++++++++++++++--- 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php new file mode 100644 index 0000000000000..171e84a65aba4 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Product; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; + +/** + * Resolve rendered content for text attributes + */ +class ProductTextAttribute implements ResolverInterface +{ + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ): array { + $value['field'] = $field->getName(); + + return $value; + } +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php index c0b67889ecd74..724d0826dbb3d 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php @@ -9,6 +9,7 @@ use Magento\Catalog\Model\Product; use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Catalog\Helper\Output as OutputHelper; @@ -41,14 +42,17 @@ public function resolve( ResolveInfo $info, array $value = null, array $args = null - ): array { + ): ?string { if (!isset($value['model'])) { - return []; + throw new GraphQlInputException(__('"model" value should be specified')); + } + if (!isset($value['field'])) { + throw new GraphQlInputException(__('"field" value should be specified')); } /* @var $product Product */ $product = $value['model']; - $fieldName = $field->getName(); + $fieldName = $value['field']; $renderedValue = $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); return $renderedValue; diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 3ffdc85a40d68..ad724c18a5c9a 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") - short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") + description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") + short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php index 7c2cda3a4551b..615e50f640380 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php @@ -44,7 +44,9 @@ public function testQueryAllFieldsSimpleProduct() attribute_set_id country_of_manufacture created_at - description + description { + html + } gift_message_available id categories { @@ -203,7 +205,9 @@ public function testQueryAllFieldsSimpleProduct() position sku } - short_description + short_description { + html + } sku small_image { path @@ -262,6 +266,7 @@ public function testQueryAllFieldsSimpleProduct() $this->assertArrayHasKey(0, $response['products']['items']); $this->assertBaseFields($product, $response['products']['items'][0]); $this->assertEavAttributes($product, $response['products']['items'][0]); + $this->assertTextEavAttributes($product, $response['products']['items'][0]); $this->assertOptions($product, $response['products']['items'][0]); $this->assertTierPrices($product, $response['products']['items'][0]); $this->assertArrayHasKey('websites', $response['products']['items'][0]); @@ -917,11 +922,9 @@ private function assertEavAttributes($product, $actualResponse) { $eavAttributes = [ 'url_key', - 'description', 'meta_description', 'meta_keyword', 'meta_title', - 'short_description', 'country_of_manufacture', 'gift_message_available', 'news_from_date', @@ -943,6 +946,31 @@ private function assertEavAttributes($product, $actualResponse) $this->assertResponseFields($actualResponse, $assertionMap); } + /** + * @param ProductInterface $product + * @param array $actualResponse + */ + private function assertTextEavAttributes($product, $actualResponse) + { + $eavAttributes = [ + 'description', + 'short_description', + ]; + $assertionMap = []; + foreach ($eavAttributes as $attributeCode) { + $expectedAttribute = $product->getCustomAttribute($attributeCode); + + $assertionMap[] = [ + 'response_field' => $this->eavAttributesToGraphQlSchemaFieldTranslator($attributeCode), + 'expected_value' => $expectedAttribute ? [ + 'html' => $expectedAttribute->getValue() + ] : null + ]; + } + + $this->assertResponseFields($actualResponse, $assertionMap); + } + /** * @param string $eavAttributeCode * @return string From 5fe9697ceec3d0192b9be5125c2cfb5f301521ba Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Wed, 24 Oct 2018 05:40:18 -0700 Subject: [PATCH 0283/1158] MAGETWO-95520: Verify that Catalog Price Rule and Customer Group Membership are persisted under long-term cookie --- .../Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index 73025023c23c8..45c6c90a76973 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -25,7 +25,6 @@ <argument name="ProductAttribute" type="string"/> </arguments> <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> <fillField selector="{{AdminProductAttributeGridSection.GridFilterFrontEndLabel}}" userInput="{{ProductAttribute}}" stepKey="navigateToAttributeEditPage1" /> <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="navigateToAttributeEditPage2" /> <waitForPageLoad stepKey="waitForPageLoad2" /> From 857908e3ef1b06ef66cfa9c2910861e90eb6bcfd Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Wed, 24 Oct 2018 16:37:54 +0300 Subject: [PATCH 0284/1158] MAGETWO-95517: Add different types of products on the quote including gift card --- .../Section/StorefrontProductInfoMainSection.xml | 1 + .../Mftf/Data/ProductAttributeOptionData.xml | 16 ++++++++++++++++ .../Catalog/Test/Mftf/Data/StoreLabelData.xml | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index 735571375866e..fae1ec331b667 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -13,5 +13,6 @@ <element name="priceTo" type="text" selector=".product-info-price .price-to"/> <element name="minPrice" type="text" selector="span[data-price-type='minPrice']"/> <element name="maxPrice" type="text" selector="span[data-price-type='minPrice']"/> + <element name="productBundleOptionsCheckbox" type="checkbox" selector="//*[@id='product-options-wrapper']//div[@class='fieldset']//label[contains(.,'{{childName}}')]/../input" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml index c575f1a5db82f..c21f23d16463e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml @@ -65,4 +65,20 @@ <data key="is_default">false</data> <data key="sort_order">0</data> </entity> + <entity name="productAttributeOption7" type="ProductAttributeOption"> + <var key="attribute_code" entityKey="attribute_code" entityType="ProductAttribute"/> + <data key="label" unique="suffix">Green</data> + <data key="is_default">false</data> + <data key="sort_order">3</data> + <requiredEntity type="StoreLabel">Option7Store0</requiredEntity> + <requiredEntity type="StoreLabel">Option8Store1</requiredEntity> + </entity> + <entity name="productAttributeOption8" type="ProductAttributeOption"> + <var key="attribute_code" entityKey="attribute_code" entityType="ProductAttribute"/> + <data key="label" unique="suffix">Red</data> + <data key="is_default">false</data> + <data key="sort_order">3</data> + <requiredEntity type="StoreLabel">Option9Store0</requiredEntity> + <requiredEntity type="StoreLabel">Option10Store1</requiredEntity> + </entity> </entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml index ce964e2d71503..0e51995ac72e8 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml @@ -56,4 +56,20 @@ <data key="store_id">1</data> <data key="label">option6</data> </entity> + <entity name="Option7Store0" type="StoreLabel"> + <data key="store_id">0</data> + <data key="label">Green</data> + </entity> + <entity name="Option8Store1" type="StoreLabel"> + <data key="store_id">1</data> + <data key="label">Green</data> + </entity> + <entity name="Option9Store0" type="StoreLabel"> + <data key="store_id">0</data> + <data key="label">Red</data> + </entity> + <entity name="Option10Store1" type="StoreLabel"> + <data key="store_id">1</data> + <data key="label">Red</data> + </entity> </entities> From 8248518ce4988324fd1e6224eb79f39d211cf41a Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 24 Oct 2018 17:25:21 +0300 Subject: [PATCH 0285/1158] MAGETWO-95853: Can't flush Images cache in admin --- .../Framework/Filesystem/Directory/Write.php | 14 +++++++------- .../Magento/Framework/Filesystem/Driver/File.php | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php index 88c03f7869581..e4b52de49d5f9 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php @@ -193,13 +193,13 @@ public function delete($path = null) } catch (FileSystemException $e) { $exceptionMessages[] = $e->getMessage(); } - } - if (!empty($exceptionMessages)) { - throw new FileSystemException( - new \Magento\Framework\Phrase( - \implode(' ', $exceptionMessages) - ) - ); + if (!empty($exceptionMessages)) { + throw new FileSystemException( + new \Magento\Framework\Phrase( + \implode(' ', $exceptionMessages) + ) + ); + } } return true; } diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index 4ba8f566f3f10..f9065e6be6190 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -405,14 +405,14 @@ public function deleteDirectory($path) $iterator = new \FilesystemIterator($path, $flags); /** @var \FilesystemIterator $entity */ foreach ($iterator as $entity) { - if ($entity->isDir()) { - try { + try { + if ($entity->isDir()) { $this->deleteDirectory($entity->getPathname()); - } catch (FileSystemException $exception) { - $exceptionMessages[] = $exception->getMessage(); + } else { + $this->deleteFile($entity->getPathname()); } - } else { - $this->deleteFile($entity->getPathname()); + } catch (FileSystemException $exception) { + $exceptionMessages[] = $exception->getMessage(); } } if (!empty($exceptionMessages)) { From c05cbea7b6df8620b9a2ee8b97cb1dbcff7b4b79 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 24 Oct 2018 17:44:29 +0300 Subject: [PATCH 0286/1158] MAGETWO-95853: Can't flush Images cache in admin --- .../Magento/Framework/Filesystem/Directory/Write.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php index e4b52de49d5f9..3c6d2b7321b82 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php @@ -189,10 +189,15 @@ public function delete($path = null) } else { try { $this->deleteFilesRecursively($absolutePath); + } catch (FileSystemException $e) { + $exceptionMessages[] = $e->getMessage(); + } + try { $this->driver->deleteDirectory($absolutePath); } catch (FileSystemException $e) { $exceptionMessages[] = $e->getMessage(); } + if (!empty($exceptionMessages)) { throw new FileSystemException( new \Magento\Framework\Phrase( From 389a16b3b2c6cf308c130b09cd08ab75c54dd88c Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Wed, 24 Oct 2018 09:49:01 -0500 Subject: [PATCH 0287/1158] ENGCOM-3257: Collect totals in placeOrder when no paymentMethod provided #18768 --- app/code/Magento/Quote/Model/QuoteManagement.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 9084ca8066301..6ed8393f80658 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -159,7 +159,7 @@ class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository * @param \Magento\Customer\Model\CustomerFactory $customerModelFactory - * @param \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory, + * @param \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper * @param StoreManagerInterface $storeManager * @param \Magento\Checkout\Model\Session $checkoutSession @@ -221,7 +221,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function createEmptyCart() { @@ -241,7 +241,7 @@ public function createEmptyCart() } /** - * {@inheritdoc} + * @inheritdoc */ public function createEmptyCartForCustomer($customerId) { @@ -257,7 +257,7 @@ public function createEmptyCartForCustomer($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function assignCustomer($cartId, $customerId, $storeId) { @@ -332,7 +332,7 @@ protected function createCustomerCart($customerId, $storeId) } /** - * {@inheritdoc} + * @inheritdoc */ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) { @@ -381,7 +381,7 @@ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCartForCustomer($customerId) { @@ -408,6 +408,8 @@ public function submit(QuoteEntity $quote, $orderData = []) } /** + * Convert quote items to order items for quote + * * @param Quote $quote * @return array */ From 2fcc1830d0a3a24dce25f986c46b97d15f3c4bae Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Wed, 24 Oct 2018 22:36:36 +0300 Subject: [PATCH 0288/1158] graphQl-44: added ComplexTextValue to graphQl module --- .../Resolver/Product/ProductTextAttribute.php | 30 +++++++++- .../ProductTextAttribute/HtmlContent.php | 60 ------------------- .../Magento/CatalogGraphQl/etc/graphql/di.xml | 7 --- .../CatalogGraphQl/etc/schema.graphqls | 8 +-- .../Resolver/ComplexTextValue/HtmlFormat.php | 38 ++++++++++++ app/code/Magento/GraphQl/etc/schema.graphqls | 4 ++ 6 files changed, 71 insertions(+), 76 deletions(-) delete mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php create mode 100644 app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php index 171e84a65aba4..febcd12f0e96f 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php @@ -10,12 +10,29 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Catalog\Model\Product; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Catalog\Helper\Output as OutputHelper; /** - * Resolve rendered content for text attributes + * Resolve rendered content for attributes where HTML content is allowed */ class ProductTextAttribute implements ResolverInterface { + /** + * @var OutputHelper + */ + private $outputHelper; + + /** + * @param OutputHelper $outputHelper + */ + public function __construct( + OutputHelper $outputHelper + ) { + $this->outputHelper = $outputHelper; + } + /** * @inheritdoc */ @@ -26,8 +43,15 @@ public function resolve( array $value = null, array $args = null ): array { - $value['field'] = $field->getName(); + if (!isset($value['model'])) { + throw new GraphQlInputException(__('"model" value should be specified')); + } + + /* @var $product Product */ + $product = $value['model']; + $fieldName = $field->getName(); + $renderedValue = $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); - return $value; + return ['html' => $renderedValue]; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php deleted file mode 100644 index 724d0826dbb3d..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute/HtmlContent.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute; - -use Magento\Catalog\Model\Product; -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Catalog\Helper\Output as OutputHelper; - -/** - * HTML content of Product Text Attribute - */ -class HtmlContent implements ResolverInterface -{ - /** - * @var OutputHelper - */ - private $outputHelper; - - /** - * @param OutputHelper $outputHelper - */ - public function __construct( - OutputHelper $outputHelper - ) { - $this->outputHelper = $outputHelper; - } - - /** - * @inheritdoc - */ - public function resolve( - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ): ?string { - if (!isset($value['model'])) { - throw new GraphQlInputException(__('"model" value should be specified')); - } - if (!isset($value['field'])) { - throw new GraphQlInputException(__('"field" value should be specified')); - } - - /* @var $product Product */ - $product = $value['model']; - $fieldName = $value['field']; - $renderedValue = $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); - - return $renderedValue; - } -} diff --git a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml index 8d4ca97001d3d..68a292ede6b4a 100644 --- a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml @@ -63,13 +63,6 @@ <argument name="collectionProcessor" xsi:type="object">Magento\Catalog\Model\Api\SearchCriteria\ProductCollectionProcessor</argument> </arguments> </type> - <type name="Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\FormatList"> - <arguments> - <argument name="formats" xsi:type="array"> - <item name="html" xsi:type="string">Magento\CatalogGraphQl\Model\Resolver\Product\ProductTextAttribute\Html</item> - </argument> - </arguments> - </type> <virtualType name="Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ProductFilterProcessor" type="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor"> <arguments> <argument name="customFilters" xsi:type="array"> diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index ad724c18a5c9a..fb7dd4ee2c8f0 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ProductTextAttribute @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") - short_description: ProductTextAttribute @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") + description: ComplexTextValue @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") + short_description: ComplexTextValue @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") @@ -556,7 +556,3 @@ type SortFields @doc(description: "SortFields contains a default value for sort default: String @doc(description: "Default value of sort fields") options: [SortField] @doc(description: "Available sort fields") } - -type ProductTextAttribute @doc(description: "Product text attribute.") { - html: String @doc(description: "Attribute HTML content") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute\\HtmlContent") -} diff --git a/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php b/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php new file mode 100644 index 0000000000000..2ec4d24017b0e --- /dev/null +++ b/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php @@ -0,0 +1,38 @@ +<?php +/** + * @author Atwix Team + * @copyright Copyright (c) 2018 Atwix (https://www.atwix.com/) + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Model\Resolver\ComplexTextValue; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; + +/** + * HTML format for complex text value. + * + * Initially, a value from parent resolver should be in HTML format, therefore, there is no any customization. + */ +class HtmlFormat implements ResolverInterface +{ + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ): ?string { + if (!isset($value['html'])) { + throw new GraphQlInputException(__('"html" value should be specified')); + } + + return $value['html']; + } +} diff --git a/app/code/Magento/GraphQl/etc/schema.graphqls b/app/code/Magento/GraphQl/etc/schema.graphqls index c6651cdde0cb3..8923776a63bcf 100644 --- a/app/code/Magento/GraphQl/etc/schema.graphqls +++ b/app/code/Magento/GraphQl/etc/schema.graphqls @@ -35,3 +35,7 @@ enum SortEnum @doc(description: "This enumeration indicates whether to return re ASC DESC } + +type ComplexTextValue { + html: String! @doc(description: "HTML format") @resolver(class: "\\Magento\\GraphQl\\Model\\Resolver\\ComplexTextValue\\HtmlFormat") +} From be525d11b45746670822462ab5c1125fd2aca7de Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Wed, 24 Oct 2018 23:13:05 +0300 Subject: [PATCH 0289/1158] graphQl-44: refactored resolver name --- ...oductTextAttribute.php => ProductComplexTextAttribute.php} | 2 +- app/code/Magento/CatalogGraphQl/etc/schema.graphqls | 4 ++-- .../testsuite/Magento/GraphQl/Catalog/ProductViewTest.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename app/code/Magento/CatalogGraphQl/Model/Resolver/Product/{ProductTextAttribute.php => ProductComplexTextAttribute.php} (95%) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php similarity index 95% rename from app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php rename to app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php index febcd12f0e96f..7cf7225d0f61c 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductTextAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php @@ -17,7 +17,7 @@ /** * Resolve rendered content for attributes where HTML content is allowed */ -class ProductTextAttribute implements ResolverInterface +class ProductComplexTextAttribute implements ResolverInterface { /** * @var OutputHelper diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index fb7dd4ee2c8f0..423283bdda7b0 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -248,8 +248,8 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\ id: Int @doc(description: "The ID number assigned to the product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\EntityIdToId") name: String @doc(description: "The product name. Customers use this name to identify the product.") sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer") - description: ComplexTextValue @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") - short_description: ComplexTextValue @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductTextAttribute") + description: ComplexTextValue @doc(description: "Detailed information about the product. The value can include simple HTML tags.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductComplexTextAttribute") + short_description: ComplexTextValue @doc(description: "A short description of the product. Its use depends on the theme.") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductComplexTextAttribute") special_price: Float @doc(description: "The discounted price of the product") special_from_date: String @doc(description: "The beginning date that a product has a special price") special_to_date: String @doc(description: "The end date that a product has a special price") diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php index 615e50f640380..1ab7ed5890472 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php @@ -266,7 +266,7 @@ public function testQueryAllFieldsSimpleProduct() $this->assertArrayHasKey(0, $response['products']['items']); $this->assertBaseFields($product, $response['products']['items'][0]); $this->assertEavAttributes($product, $response['products']['items'][0]); - $this->assertTextEavAttributes($product, $response['products']['items'][0]); + $this->assertComplexTextAttributes($product, $response['products']['items'][0]); $this->assertOptions($product, $response['products']['items'][0]); $this->assertTierPrices($product, $response['products']['items'][0]); $this->assertArrayHasKey('websites', $response['products']['items'][0]); @@ -950,7 +950,7 @@ private function assertEavAttributes($product, $actualResponse) * @param ProductInterface $product * @param array $actualResponse */ - private function assertTextEavAttributes($product, $actualResponse) + private function assertComplexTextAttributes($product, $actualResponse) { $eavAttributes = [ 'description', From 1a745a5db170b77ed92b6d71444bc8c8e0f0aa3e Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Wed, 24 Oct 2018 15:47:58 -0500 Subject: [PATCH 0290/1158] MAGETWO-95798: All country state's are shown for USA when shipping form has custom address attributes. --- .../Ui/view/base/web/js/form/element/region.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/region.js b/app/code/Magento/Ui/view/base/web/js/form/element/region.js index 45d38b339b50b..f6eafcf49284d 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/region.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/region.js @@ -78,13 +78,12 @@ define([ * @param {String} field */ filter: function (value, field) { - var country = registry.get(this.parentName + '.' + 'country_id'), - option; + var superFn = this._super; - if (country) { - option = country.indexedOptions[value]; + registry.get(this.parentName + '.' + 'country_id', function (country) { + var option = country.indexedOptions[value]; - this._super(value, field); + superFn.call(this, value, field); if (option && option['is_region_visible'] === false) { // hide select and corresponding text input field if region must not be shown for selected country @@ -94,7 +93,7 @@ define([ this.toggleInput(false); } } - } + }.bind(this)); } }); }); From 9d958bbb4103361b2004dcc620a5c9b1b6e4437b Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Thu, 25 Oct 2018 10:40:02 +0300 Subject: [PATCH 0291/1158] MAGETWO-95517: Add different types of products on the quote including gift card --- .../Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index 73025023c23c8..45c6c90a76973 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -25,7 +25,6 @@ <argument name="ProductAttribute" type="string"/> </arguments> <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> <fillField selector="{{AdminProductAttributeGridSection.GridFilterFrontEndLabel}}" userInput="{{ProductAttribute}}" stepKey="navigateToAttributeEditPage1" /> <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="navigateToAttributeEditPage2" /> <waitForPageLoad stepKey="waitForPageLoad2" /> From bf0030fbbd49ce1c40a17bd1f0717a9dffeb326d Mon Sep 17 00:00:00 2001 From: Ronak Patel <ronak2ram@gmail.com> Date: Thu, 25 Oct 2018 13:12:00 +0530 Subject: [PATCH 0292/1158] Update blocks --- app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php | 5 ++++- .../Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php b/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php index 962127e16f716..d7c0008c7d927 100644 --- a/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php +++ b/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php @@ -78,7 +78,10 @@ private function getBlocksData(array $blockIdentifiers): array $blocksData = []; try { foreach ($blockIdentifiers as $blockIdentifier) { - $blocksData[$blockIdentifier] = $this->blockDataProvider->getData($blockIdentifier); + $blockData = $this->blockDataProvider->getData($blockIdentifier); + if (!empty($blockData)) { + $blocksData[$blockIdentifier] = $blockData; + } } } catch (NoSuchEntityException $e) { throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); diff --git a/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php b/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php index 5b7e632a73cb0..d47a0dca27157 100644 --- a/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php +++ b/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php @@ -49,7 +49,7 @@ public function getData(string $blockIdentifier): array $block = $this->blockRepository->getById($blockIdentifier); if (false === $block->isActive()) { - throw new NoSuchEntityException(); + return []; } $renderedContent = $this->widgetFilter->filter($block->getContent()); From 42e3fd5fa39beee02c9f03e7cda6a1165e34482e Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 25 Oct 2018 02:01:26 -0700 Subject: [PATCH 0293/1158] MAGETWO-95520: Verify that Catalog Price Rule and Customer Group Membership are persisted under long-term cookie --- .../Mftf/ActionGroup/AdminProductAttributeActionGroup.xml | 1 - .../Magento/Persistent/Test/Mftf/Data/PersistentData.xml | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index 45c6c90a76973..ddd73b4191afc 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -13,7 +13,6 @@ <argument name="ProductAttribute"/> </arguments> <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" userInput="{{ProductAttribute.attribute_code}}" stepKey="setAttributeCode"/> <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="searchForAttributeFromTheGrid"/> diff --git a/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml b/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml index 3d42ae6da81a5..39e55693811e9 100644 --- a/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml +++ b/app/code/Magento/Persistent/Test/Mftf/Data/PersistentData.xml @@ -22,16 +22,16 @@ </entity> <entity name="PersistentLogoutClearEnabled" type="persistent_config_state"> - <requiredEntity type="persistent_options_logout_clear">persistentEnabledLogoutClear</requiredEntity> + <requiredEntity type="persistent_options_logout_clear">PersistentEnabledLogoutClear</requiredEntity> </entity> - <entity name="persistentEnabledLogoutClear" type="logout_clear"> + <entity name="PersistentEnabledLogoutClear" type="logout_clear"> <data key="value">1</data> </entity> <entity name="PersistentLogoutClearDisable" type="persistent_config_state"> - <requiredEntity type="persistent_options_logout_clear">persistentDisableLogoutClear</requiredEntity> + <requiredEntity type="persistent_options_logout_clear">PersistentDisableLogoutClear</requiredEntity> </entity> - <entity name="persistentDisableLogoutClear" type="logout_clear"> + <entity name="PersistentDisableLogoutClear" type="logout_clear"> <data key="value">0</data> </entity> </entities> From 4349d022166c905e4bd77f3bfb36118c7310ff19 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 25 Oct 2018 11:08:56 +0200 Subject: [PATCH 0294/1158] Run tests without magento installation --- dev/travis/before_script.sh | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index c27e65d3897c7..135152928539c 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -138,25 +138,27 @@ case $TEST_SUITE in api-functional) echo "Installing Magento" mysql -uroot -e 'CREATE DATABASE magento2;' - php bin/magento setup:install -q \ - --language="en_US" \ - --timezone="UTC" \ - --currency="USD" \ - --base-url="http://${MAGENTO_HOST_NAME}/" \ - --admin-firstname="John" \ - --admin-lastname="Doe" \ - --backend-frontname="backend" \ - --admin-email="admin@example.com" \ - --admin-user="admin" \ - --use-rewrites=1 \ - --admin-use-security-key=0 \ - --admin-password="123123q" - - echo "Enabling production mode" - php bin/magento deploy:mode:set production +# php bin/magento setup:install -q \ +# --language="en_US" \ +# --timezone="UTC" \ +# --currency="USD" \ +# --base-url="http://${MAGENTO_HOST_NAME}/" \ +# --admin-firstname="John" \ +# --admin-lastname="Doe" \ +# --backend-frontname="backend" \ +# --admin-email="admin@example.com" \ +# --admin-user="admin" \ +# --use-rewrites=1 \ +# --admin-use-security-key=0 \ +# --admin-password="123123q" + +# echo "Enabling production mode" +# php bin/magento deploy:mode:set production echo "Prepare api-functional tests for running" cd dev/tests/api-functional + cp config/install-config-mysql.php.dist config/install-config-mysql.php + sed -e "s?http://localhost/?http://${MAGENTO_HOST_NAME}/?g" --in-place ./config/install-config-mysql.php cp ./phpunit_graphql.xml.dist ./phpunit.xml sed -e "s?magento.url?${MAGENTO_HOST_NAME}?g" --in-place ./phpunit.xml From ccfffbc78a4e2c0204c0f16e8b1ff32316f5f7c1 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 25 Oct 2018 14:27:13 +0200 Subject: [PATCH 0295/1158] Deploy test modules before api-functional tests --- .travis.yml | 4 ++-- dev/travis/before_install.sh | 2 +- dev/travis/before_script.sh | 39 ++++++++++++++++++------------------ 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 930172a9ea6e0..25b18949f0386 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ env: # - TEST_SUITE=integration INTEGRATION_INDEX=2 # - TEST_SUITE=integration INTEGRATION_INDEX=3 # - TEST_SUITE=functional - - TEST_SUITE=api-functional + - TEST_SUITE=graphql-api-functional matrix: exclude: - php: 7.1 @@ -66,4 +66,4 @@ script: - if [ $TEST_SUITE == "functional" ]; then dev/tests/functional/vendor/phpunit/phpunit/phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js"] && [ $TEST_SUITE != "api" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - if [ $TEST_SUITE == "js" ]; then grunt $GRUNT_COMMAND; fi - - if [ $TEST_SUITE == "api-functional" ]; then phpunit -c dev/tests/api-functional; fi + - if [ $TEST_SUITE == "graphql-api-functional" ]; then phpunit -c dev/tests/api-functional; fi diff --git a/dev/travis/before_install.sh b/dev/travis/before_install.sh index 44ba3fd8b74f1..845d70e4e79fd 100755 --- a/dev/travis/before_install.sh +++ b/dev/travis/before_install.sh @@ -34,7 +34,7 @@ if [ $TEST_SUITE == "js" ]; then yarn global add grunt-cli fi -if [ $TEST_SUITE = "functional" ] || [ $TEST_SUITE = "api-functional" ]; then +if [ $TEST_SUITE = "functional" ] || [ $TEST_SUITE = "graphql-api-functional" ]; then # Install apache sudo apt-get update sudo apt-get install apache2 libapache2-mod-fastcgi diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index 135152928539c..64591e8112cef 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -135,34 +135,35 @@ case $TEST_SUITE in cd ../../.. ;; - api-functional) + graphql-api-functional) echo "Installing Magento" mysql -uroot -e 'CREATE DATABASE magento2;' -# php bin/magento setup:install -q \ -# --language="en_US" \ -# --timezone="UTC" \ -# --currency="USD" \ -# --base-url="http://${MAGENTO_HOST_NAME}/" \ -# --admin-firstname="John" \ -# --admin-lastname="Doe" \ -# --backend-frontname="backend" \ -# --admin-email="admin@example.com" \ -# --admin-user="admin" \ -# --use-rewrites=1 \ -# --admin-use-security-key=0 \ -# --admin-password="123123q" - -# echo "Enabling production mode" -# php bin/magento deploy:mode:set production + php bin/magento setup:install -q \ + --language="en_US" \ + --timezone="UTC" \ + --currency="USD" \ + --base-url="http://${MAGENTO_HOST_NAME}/" \ + --admin-firstname="John" \ + --admin-lastname="Doe" \ + --backend-frontname="backend" \ + --admin-email="admin@example.com" \ + --admin-user="admin" \ + --use-rewrites=1 \ + --admin-use-security-key=0 \ + --admin-password="123123q" + + echo "Enabling production mode" + php bin/magento deploy:mode:set production echo "Prepare api-functional tests for running" cd dev/tests/api-functional - cp config/install-config-mysql.php.dist config/install-config-mysql.php - sed -e "s?http://localhost/?http://${MAGENTO_HOST_NAME}/?g" --in-place ./config/install-config-mysql.php + cp -r _files/Magento/* ../../../app/code/Magento # Deploy and enable test modules before running tests + php ../../../bin/magento setup:upgrade cp ./phpunit_graphql.xml.dist ./phpunit.xml sed -e "s?magento.url?${MAGENTO_HOST_NAME}?g" --in-place ./phpunit.xml cd ../../.. + php bin/magento setup:upgrade ;; esac From 33f40d63ee1d102e81822341fadeb4cd5af68997 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 25 Oct 2018 14:50:06 +0200 Subject: [PATCH 0296/1158] Remove redundant setup:upgrade --- .travis.yml | 2 +- dev/travis/before_script.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 25b18949f0386..db42be9f1e217 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ matrix: - php: 7.1 env: TEST_SUITE=functional - php: 7.1 - env: TEST_SUITE=api-functional + env: TEST_SUITE=graphql-api-functional cache: apt: true directories: diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index 64591e8112cef..8b5dcab310418 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -158,7 +158,6 @@ case $TEST_SUITE in echo "Prepare api-functional tests for running" cd dev/tests/api-functional cp -r _files/Magento/* ../../../app/code/Magento # Deploy and enable test modules before running tests - php ../../../bin/magento setup:upgrade cp ./phpunit_graphql.xml.dist ./phpunit.xml sed -e "s?magento.url?${MAGENTO_HOST_NAME}?g" --in-place ./phpunit.xml From 41bf2a1485ead39c75d97cccc819c9cc2091f0ca Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 25 Oct 2018 15:11:04 +0200 Subject: [PATCH 0297/1158] Enable back other tests --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index db42be9f1e217..78b088c9d848d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,14 @@ env: - NODE_JS_VERSION=8 - MAGENTO_HOST_NAME="magento2.travis" matrix: -# - TEST_SUITE=unit -# - TEST_SUITE=static -# - TEST_SUITE=js GRUNT_COMMAND=spec -# - TEST_SUITE=js GRUNT_COMMAND=static -# - TEST_SUITE=integration INTEGRATION_INDEX=1 -# - TEST_SUITE=integration INTEGRATION_INDEX=2 -# - TEST_SUITE=integration INTEGRATION_INDEX=3 -# - TEST_SUITE=functional + - TEST_SUITE=unit + - TEST_SUITE=static + - TEST_SUITE=js GRUNT_COMMAND=spec + - TEST_SUITE=js GRUNT_COMMAND=static + - TEST_SUITE=integration INTEGRATION_INDEX=1 + - TEST_SUITE=integration INTEGRATION_INDEX=2 + - TEST_SUITE=integration INTEGRATION_INDEX=3 + - TEST_SUITE=functional - TEST_SUITE=graphql-api-functional matrix: exclude: From 9cc9cf7fdc0067192fde233c1f3d5d6979ea862f Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Thu, 25 Oct 2018 16:56:12 +0300 Subject: [PATCH 0298/1158] MAGETWO-95833: Shared gift registry does not show the special price for a configurable product - Use simple product to get price. --- .../Block/Cart/Item/Renderer/Configurable.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php index 3b657dd1ab2d0..77110975401ff 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php @@ -70,4 +70,14 @@ public function getIdentities() } return $identities; } + + /** + * Get price for exact simple product added to cart + * + * @inheritdoc + */ + public function getProductPriceHtml(\Magento\Catalog\Model\Product $product) + { + return parent::getProductPriceHtml($this->getChildProduct()); + } } From 879961ccdc740003f9e83fdc2057a1e141db65da Mon Sep 17 00:00:00 2001 From: vprohorov <vitaliy_prokharau@epam.com> Date: Wed, 24 Oct 2018 15:33:29 +0300 Subject: [PATCH 0299/1158] MAGETWO-95821: Order fails on review step if gift card applied - Adding exception for orders with zero grandTotal --- .../Controller/Express/AbstractExpress.php | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php b/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php index 571d73d07b68e..fa131f9591fa9 100644 --- a/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php +++ b/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php @@ -7,12 +7,17 @@ use Magento\Checkout\Controller\Express\RedirectLoginInterface; use Magento\Framework\App\Action\Action as AppAction; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; /** * Abstract Express Checkout Controller * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -abstract class AbstractExpress extends AppAction implements RedirectLoginInterface +abstract class AbstractExpress extends AppAction implements + RedirectLoginInterface, + HttpGetActionInterface, + HttpPostActionInterface { /** * @var \Magento\Paypal\Model\Express\Checkout @@ -137,6 +142,14 @@ protected function _initCheckout() $this->getResponse()->setStatusHeader(403, '1.1', 'Forbidden'); throw new \Magento\Framework\Exception\LocalizedException(__('We can\'t initialize Express Checkout.')); } + if (!(float)$quote->getGrandTotal()) { + throw new \Magento\Framework\Exception\LocalizedException( + __( + 'PayPal can\'t process orders with a zero balance due. ' + . 'To finish your purchase, please go through the standard checkout process.' + ) + ); + } if (!isset($this->_checkoutTypes[$this->_checkoutType])) { $parameters = [ 'params' => [ @@ -151,6 +164,8 @@ protected function _initCheckout() } /** + * Get Proper Checkout Token + * * Search for proper checkout token in request or session or (un)set specified one * Combined getter/setter * @@ -221,8 +236,7 @@ protected function _getQuote() } /** - * Returns before_auth_url redirect parameter for customer session - * @return null + * @inheritdoc */ public function getCustomerBeforeAuthUrl() { @@ -230,8 +244,7 @@ public function getCustomerBeforeAuthUrl() } /** - * Returns a list of action flags [flag_key] => boolean - * @return array + * @inheritdoc */ public function getActionFlagList() { @@ -240,6 +253,7 @@ public function getActionFlagList() /** * Returns login url parameter for redirect + * * @return string */ public function getLoginUrl() @@ -249,6 +263,7 @@ public function getLoginUrl() /** * Returns action name which requires redirect + * * @return string */ public function getRedirectActionName() @@ -269,4 +284,9 @@ public function redirectLogin() $this->_urlHelper->addRequestParam($this->_customerUrl->getLoginUrl(), ['context' => 'checkout']) ); } + + /** + * @inheritdoc + */ + abstract public function execute(); } From f82912dc75d57694b056ca6a7ca198fde1e6b108 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Thu, 25 Oct 2018 18:34:19 +0300 Subject: [PATCH 0300/1158] graphQl-44: fixed copyrights --- .../GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php b/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php index 2ec4d24017b0e..fffca765faba6 100644 --- a/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php +++ b/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php @@ -1,7 +1,7 @@ <?php /** - * @author Atwix Team - * @copyright Copyright (c) 2018 Atwix (https://www.atwix.com/) + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ declare(strict_types=1); From afe43948a64f0882112f79eb3dc29fbbb02713e9 Mon Sep 17 00:00:00 2001 From: Tom Richards <tom.r@delegator.com> Date: Thu, 25 Oct 2018 15:30:32 -0400 Subject: [PATCH 0301/1158] Replace erroneous usage of unsData method --- .../Magento/GroupedProduct/Model/Product/Type/Grouped.php | 2 +- .../Test/Unit/Model/Product/Type/GroupedTest.php | 4 ++-- .../Magento/Reports/Model/Product/Index/AbstractIndex.php | 2 +- .../testsuite/Magento/Newsletter/Controller/ManageTest.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 80824d45cb6e5..673450838fb94 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -236,7 +236,7 @@ public function getAssociatedProducts($product) */ public function flushAssociatedProductsCache($product) { - return $product->unsData($this->_keyAssociatedProducts); + return $product->unsetData($this->_keyAssociatedProducts); } /** diff --git a/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php b/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php index 06c07a8dc34a8..e50d6491a6aca 100644 --- a/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php +++ b/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php @@ -611,9 +611,9 @@ public function testPrepareForCartAdvancedZeroQty() public function testFlushAssociatedProductsCache() { - $productMock = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['unsData']); + $productMock = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['unsetData']); $productMock->expects($this->once()) - ->method('unsData') + ->method('unsetData') ->with('_cache_instance_associated_products') ->willReturnSelf(); $this->assertEquals($productMock, $this->_model->flushAssociatedProductsCache($productMock)); diff --git a/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php b/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php index 5682892a77c60..56991e290dec6 100644 --- a/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php +++ b/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php @@ -252,7 +252,7 @@ public function clean() public function registerIds($productIds) { $this->_getResource()->registerIds($this, $productIds); - $this->_getSession()->unsData($this->_countCacheKey); + $this->_getSession()->unsetData($this->_countCacheKey); return $this; } } diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php index 5a094eb05c774..175c1c7c6c668 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php @@ -40,7 +40,7 @@ protected function setUp() protected function tearDown() { $this->customerSession->setCustomerId(null); - $this->coreSession->unsData('_form_key'); + $this->coreSession->unsetData('_form_key'); } /** From 3d0d8b7674c6798c3907cb77e690f62ef5310592 Mon Sep 17 00:00:00 2001 From: Mahesh Singh <mahesh721@webkul.com> Date: Fri, 26 Oct 2018 01:46:45 +0530 Subject: [PATCH 0302/1158] Issue #18150 fixed --- app/code/Magento/Backup/Controller/Adminhtml/Index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index.php b/app/code/Magento/Backup/Controller/Adminhtml/Index.php index dcafbc7370d2d..142211fe90a44 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index.php @@ -19,7 +19,7 @@ abstract class Index extends \Magento\Backend\App\Action * * @see _isAllowed() */ - const ADMIN_RESOURCE = 'Magento_Backend::backup'; + const ADMIN_RESOURCE = 'Magento_Backup::backup'; /** * Core registry From c58ac50f9f090e2094639b006dca414b13a225d5 Mon Sep 17 00:00:00 2001 From: Jason Evans <evans022@gmail.com> Date: Thu, 25 Oct 2018 16:29:39 -0500 Subject: [PATCH 0303/1158] Issue #14571 - Wrong column type when creating temporary tables for flat catalog --- .../Indexer/Product/Flat/TableBuilder.php | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php index a32379b8c0a67..a3d958ea537e1 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php @@ -7,6 +7,9 @@ use Magento\Catalog\Model\Indexer\Product\Flat\Table\BuilderInterfaceFactory; +/** + * Class TableBuilder + */ class TableBuilder { /** @@ -137,13 +140,23 @@ protected function _createTemporaryTable($tableName, array $columns, $valueField ); $flatColumns = $this->_productIndexerHelper->getFlatColumns(); - $temporaryTableBuilder->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); + $temporaryTableBuilder->addColumn( + 'entity_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned'=>true] + ); $temporaryTableBuilder->addColumn('type_id', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT); $temporaryTableBuilder->addColumn('attribute_set_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); - $valueTemporaryTableBuilder->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); + $valueTemporaryTableBuilder->addColumn( + 'entity_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned'=>true] + ); /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ foreach ($columns as $columnName => $attribute) { @@ -198,9 +211,10 @@ protected function _getTemporaryTableName($tableName) * Fill temporary entity table * * @param string $tableName - * @param array $columns - * @param array $changedIds + * @param array $columns + * @param array $changedIds * @return void + * @throws \Exception */ protected function _fillTemporaryEntityTable($tableName, array $columns, array $changedIds = []) { @@ -244,11 +258,12 @@ protected function _addPrimaryKeyToTable($tableName, $columnName = 'entity_id') * Fill temporary table by data from products EAV attributes by type * * @param string $tableName - * @param array $tableColumns - * @param array $changedIds + * @param array $tableColumns + * @param array $changedIds * @param string $valueFieldSuffix * @param int $storeId * @return void + * @throws \Exception */ protected function _fillTemporaryTable( $tableName, @@ -345,6 +360,8 @@ protected function _fillTemporaryTable( } /** + * Get Metadata Pool + * * @return \Magento\Framework\EntityManager\MetadataPool * @deprecated 101.1.0 */ From 86a30b6295fec501b0ecaa27e173bcdefc8fa95b Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Tue, 16 Oct 2018 09:04:53 -0400 Subject: [PATCH 0304/1158] Write intercepted mapping to generated/metadata during compilation This prevents the intercepted cache from being cleared following compilation. The mapping is stored in the frontend cache when the mapping metadata file is not present, ie developer, default modes. Fixes #17680 --- .../Framework/Interception/Config/Config.php | 111 ++++++++++++++---- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/lib/internal/Magento/Framework/Interception/Config/Config.php b/lib/internal/Magento/Framework/Interception/Config/Config.php index 7c80051537baa..9011ddac769bd 100644 --- a/lib/internal/Magento/Framework/Interception/Config/Config.php +++ b/lib/internal/Magento/Framework/Interception/Config/Config.php @@ -78,6 +78,16 @@ class Config implements \Magento\Framework\Interception\ConfigInterface */ private $serializer; + /** + * @var \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem + */ + private $configWriter; + + /** + * @var \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled + */ + private $compiledLoader; + /** * Config constructor * @@ -89,6 +99,8 @@ class Config implements \Magento\Framework\Interception\ConfigInterface * @param \Magento\Framework\ObjectManager\DefinitionInterface $classDefinitions * @param string $cacheId * @param SerializerInterface|null $serializer + * @param \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem $configWriter + * @param \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader */ public function __construct( \Magento\Framework\Config\ReaderInterface $reader, @@ -98,7 +110,9 @@ public function __construct( \Magento\Framework\Interception\ObjectManager\ConfigInterface $omConfig, \Magento\Framework\ObjectManager\DefinitionInterface $classDefinitions, $cacheId = 'interception', - SerializerInterface $serializer = null + SerializerInterface $serializer = null, + \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem $configWriter = null, + \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader = null ) { $this->_omConfig = $omConfig; $this->_relations = $relations; @@ -109,11 +123,15 @@ public function __construct( $this->_scopeList = $scopeList; $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() ->get(Serialize::class); - $intercepted = $this->_cache->load($this->_cacheId); + $this->configWriter = $configWriter ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem::class); + $this->compiledLoader = $compiledLoader ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class); + $intercepted = $this->loadIntercepted(); if ($intercepted !== false) { - $this->_intercepted = $this->serializer->unserialize($intercepted); + $this->_intercepted = $intercepted; } else { - $this->initialize($this->_classDefinitions->getClasses()); + $this->initializeUncompiled($this->_classDefinitions->getClasses()); } } @@ -125,24 +143,9 @@ public function __construct( */ public function initialize($classDefinitions = []) { - $this->_cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [$this->_cacheId]); - $config = []; - foreach ($this->_scopeList->getAllScopes() as $scope) { - $config = array_replace_recursive($config, $this->_reader->read($scope)); - } - unset($config['preferences']); - foreach ($config as $typeName => $typeConfig) { - if (!empty($typeConfig['plugins'])) { - $this->_intercepted[ltrim($typeName, '\\')] = true; - } - } - foreach ($config as $typeName => $typeConfig) { - $this->hasPlugins($typeName); - } - foreach ($classDefinitions as $class) { - $this->hasPlugins($class); - } - $this->_cache->save($this->serializer->serialize($this->_intercepted), $this->_cacheId); + $this->generateIntercepted($classDefinitions); + + $this->configWriter->write($this->_cacheId, $this->_intercepted); } /** @@ -188,4 +191,68 @@ public function hasPlugins($type) } return $this->_inheritInterception($type); } + + /** + * Write interception config to cache + * + * @param array $classDefinitions + */ + private function initializeUncompiled($classDefinitions = []) + { + $this->_cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [$this->_cacheId]); + + $this->generateIntercepted($classDefinitions); + + $this->_cache->save($this->serializer->serialize($this->_intercepted), $this->_cacheId); + } + + /** + * Generate intercepted array to store in compiled metadata or frontend cache + * + * @param $classDefinitions + */ + private function generateIntercepted($classDefinitions) + { + $config = []; + foreach ($this->_scopeList->getAllScopes() as $scope) { + $config = array_replace_recursive($config, $this->_reader->read($scope)); + } + unset($config['preferences']); + foreach ($config as $typeName => $typeConfig) { + if (!empty($typeConfig['plugins'])) { + $this->_intercepted[ltrim($typeName, '\\')] = true; + } + } + foreach ($config as $typeName => $typeConfig) { + $this->hasPlugins($typeName); + } + foreach ($classDefinitions as $class) { + $this->hasPlugins($class); + } + } + + /** + * Load the interception config from cache + * + * @return array|false + */ + private function loadIntercepted() + { + if ($this->isCompiled()) { + return $this->compiledLoader->load($this->_cacheId); + } + + $intercepted = $this->_cache->load($this->_cacheId); + return $intercepted ? $this->serializer->unserialize($intercepted) : false; + } + + /** + * Check for the compiled config with the generated metadata + * + * @return bool + */ + private function isCompiled() + { + return file_exists(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::getFilePath($this->_cacheId)); + } } From 32191691b5e66da54c422b4968590b7c581c0e58 Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Thu, 18 Oct 2018 08:59:30 -0400 Subject: [PATCH 0305/1158] Move ObjectManager Config Writer to Framework The ObjectManager Config Writer class currently lives in the Setup module and is needed in the Framework when writing the interception config to the filesystem during compilation. This commit adds the classes to the Framework and replaces any existing usage with the new interface/class. --- .../ConfigWriter/FilesystemTest.php | 59 ++++++++++++++++++ .../ObjectManager/ConfigWriter/Filesystem.php | 61 +++++++++++++++++++ .../ObjectManager/ConfigWriterInterface.php | 24 ++++++++ .../Framework/Interception/Config/Config.php | 8 +-- .../Console/Command/DiCompileCommand.php | 4 +- .../Module/Di/App/Task/Operation/Area.php | 6 +- .../Di/Compiler/Config/Writer/Filesystem.php | 4 ++ .../Di/Compiler/Config/WriterInterface.php | 3 +- .../Test/Unit/Module/Di/App/Task/AreaTest.php | 2 +- 9 files changed, 160 insertions(+), 11 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigWriter/FilesystemTest.php create mode 100644 lib/internal/Magento/Framework/App/ObjectManager/ConfigWriter/Filesystem.php create mode 100644 lib/internal/Magento/Framework/App/ObjectManager/ConfigWriterInterface.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigWriter/FilesystemTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigWriter/FilesystemTest.php new file mode 100644 index 0000000000000..843be22c57d67 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigWriter/FilesystemTest.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\App\ObjectManager\ConfigWriter; + +class FilesystemTest extends \PHPUnit\Framework\TestCase +{ + const CACHE_KEY = 'filesystemtest'; + + /** + * @var \Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem + */ + private $configWriter; + + /** + * @var \Magento\Framework\App\ObjectManager\ConfigLoader + */ + private $configReader; + + protected function setUp() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->configWriter = $objectManager->create( + \Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class + ); + $this->configReader = $objectManager->create( + \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class + ); + } + + public function testWrite() + { + $sampleData = [ + 'classA' => true, + 'classB' => false, + ]; + + $this->configWriter->write(self::CACHE_KEY, $sampleData); + $this->assertEquals($sampleData, $this->configReader->load(self::CACHE_KEY)); + } + + public function testOverwrite() + { + $this->configWriter->write(self::CACHE_KEY, ['hello' => 'world']); + + $sampleData = [ + 'classC' => false, + 'classD' => true, + ]; + + $this->configWriter->write(self::CACHE_KEY, $sampleData); + $this->assertEquals($sampleData, $this->configReader->load(self::CACHE_KEY)); + } +} diff --git a/lib/internal/Magento/Framework/App/ObjectManager/ConfigWriter/Filesystem.php b/lib/internal/Magento/Framework/App/ObjectManager/ConfigWriter/Filesystem.php new file mode 100644 index 0000000000000..2b1cdd2a9c10b --- /dev/null +++ b/lib/internal/Magento/Framework/App/ObjectManager/ConfigWriter/Filesystem.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\App\ObjectManager\ConfigWriter; + +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager\ConfigWriterInterface; + +/** + * @inheritdoc + */ +class Filesystem implements ConfigWriterInterface +{ + /** + * @var DirectoryList + */ + private $directoryList; + + /** + * @param DirectoryList $directoryList + */ + public function __construct( + DirectoryList $directoryList + ) { + $this->directoryList = $directoryList; + } + + /** + * Writes config in storage + * + * @param string $key + * @param array $config + * @return void + */ + public function write(string $key, array $config) + { + $this->initialize(); + $configuration = sprintf('<?php return %s;', var_export($config, true)); + file_put_contents( + $this->directoryList->getPath(DirectoryList::GENERATED_METADATA) . '/' . $key . '.php', + $configuration + ); + } + + /** + * Initializes writer + * + * @return void + */ + private function initialize() + { + if (!file_exists($this->directoryList->getPath(DirectoryList::GENERATED_METADATA))) { + mkdir($this->directoryList->getPath(DirectoryList::GENERATED_METADATA)); + } + } +} diff --git a/lib/internal/Magento/Framework/App/ObjectManager/ConfigWriterInterface.php b/lib/internal/Magento/Framework/App/ObjectManager/ConfigWriterInterface.php new file mode 100644 index 0000000000000..cccbb0ae30b99 --- /dev/null +++ b/lib/internal/Magento/Framework/App/ObjectManager/ConfigWriterInterface.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\App\ObjectManager; + +/** + * Write compiled object manager configuration to storage + */ +interface ConfigWriterInterface +{ + /** + * Writes config in storage + * + * @param string $key + * @param array $config + * @return void + */ + public function write(string $key, array $config); +} diff --git a/lib/internal/Magento/Framework/Interception/Config/Config.php b/lib/internal/Magento/Framework/Interception/Config/Config.php index 9011ddac769bd..9a7845e96006b 100644 --- a/lib/internal/Magento/Framework/Interception/Config/Config.php +++ b/lib/internal/Magento/Framework/Interception/Config/Config.php @@ -79,7 +79,7 @@ class Config implements \Magento\Framework\Interception\ConfigInterface private $serializer; /** - * @var \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem + * @var \Magento\Framework\App\ObjectManager\ConfigWriterInterface */ private $configWriter; @@ -99,7 +99,7 @@ class Config implements \Magento\Framework\Interception\ConfigInterface * @param \Magento\Framework\ObjectManager\DefinitionInterface $classDefinitions * @param string $cacheId * @param SerializerInterface|null $serializer - * @param \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem $configWriter + * @param \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter * @param \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader */ public function __construct( @@ -111,7 +111,7 @@ public function __construct( \Magento\Framework\ObjectManager\DefinitionInterface $classDefinitions, $cacheId = 'interception', SerializerInterface $serializer = null, - \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem $configWriter = null, + \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter = null, \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader = null ) { $this->_omConfig = $omConfig; @@ -124,7 +124,7 @@ public function __construct( $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() ->get(Serialize::class); $this->configWriter = $configWriter ?: \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem::class); + ->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); $this->compiledLoader = $compiledLoader ?: \Magento\Framework\App\ObjectManager::getInstance() ->get(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class); $intercepted = $this->loadIntercepted(); diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php index 68e26ec83c3f7..ee26e71d94f30 100644 --- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php @@ -307,8 +307,8 @@ private function configureObjectManager(OutputInterface $output) { $this->objectManager->configure( [ - 'preferences' => [\Magento\Setup\Module\Di\Compiler\Config\WriterInterface::class => - \Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem::class, + 'preferences' => [\Magento\Framework\App\ObjectManager\ConfigWriterInterface::class => + \Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class, ], \Magento\Setup\Module\Di\Compiler\Config\ModificationChain::class => [ 'arguments' => [ 'modificationsList' => [ diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php index ec5fb3f94e4b4..7acc84e356c4d 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php @@ -28,7 +28,7 @@ class Area implements OperationInterface private $configReader; /** - * @var Config\WriterInterface + * @var \Magento\Framework\App\ObjectManager\ConfigWriterInterface */ private $configWriter; @@ -46,7 +46,7 @@ class Area implements OperationInterface * @param App\AreaList $areaList * @param \Magento\Setup\Module\Di\Code\Reader\Decorator\Area $areaInstancesNamesList * @param Config\Reader $configReader - * @param Config\WriterInterface $configWriter + * @param \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter * @param \Magento\Setup\Module\Di\Compiler\Config\ModificationChain $modificationChain * @param array $data */ @@ -54,7 +54,7 @@ public function __construct( App\AreaList $areaList, \Magento\Setup\Module\Di\Code\Reader\Decorator\Area $areaInstancesNamesList, Config\Reader $configReader, - Config\WriterInterface $configWriter, + \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter, Config\ModificationChain $modificationChain, $data = [] ) { diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php index b4601a970de87..ee9321c5d4199 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php @@ -10,6 +10,10 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Setup\Module\Di\Compiler\Config\WriterInterface; +/** + * @deprecated Moved to Framework to allow broader reuse + * @see \Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem + */ class Filesystem implements WriterInterface { /** diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php index 9e6a3008283dc..1ff5524529cc4 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php @@ -9,7 +9,8 @@ /** * Interface \Magento\Setup\Module\Di\Compiler\Config\WriterInterface - * + * @deprecated Moved to Framework to allow broader reuse + * @see \Magento\Framework\App\ObjectManager\ConfigWriterInterface */ interface WriterInterface { diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php index 39e67401760b7..03b423bb32b0f 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php @@ -48,7 +48,7 @@ protected function setUp() $this->configReaderMock = $this->getMockBuilder(\Magento\Setup\Module\Di\Compiler\Config\Reader::class) ->disableOriginalConstructor() ->getMock(); - $this->configWriterMock = $this->getMockBuilder(\Magento\Setup\Module\Di\Compiler\Config\WriterInterface::class) + $this->configWriterMock = $this->getMockBuilder(\Magento\Framework\App\ObjectManager\ConfigWriterInterface::class) ->disableOriginalConstructor() ->getMock(); $this->configChain = $this->getMockBuilder(\Magento\Setup\Module\Di\Compiler\Config\ModificationChain::class) From a901ad3fd5390c455409d1b8e09af8190debd26c Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Fri, 19 Oct 2018 16:52:03 -0400 Subject: [PATCH 0306/1158] Add Interception Config Integration Test Test load logic added for persisting compiled cache data in `generated/metadata` --- .../Interception/Config/ConfigTest.php | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php new file mode 100644 index 0000000000000..5221b8bb422cf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php @@ -0,0 +1,136 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\Interception\Config; + +use Magento\Framework\App\Filesystem\DirectoryList; + +class ConfigTest extends \PHPUnit\Framework\TestCase +{ + const CACHE_ID = 'interceptiontest'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var \Magento\Framework\Serialize\SerializerInterface + */ + private $serializer; + + /** + * @var \Magento\Framework\Cache\FrontendInterface + */ + private $cache; + + /** + * @var \Magento\Framework\App\ObjectManager\ConfigWriterInterface + */ + private $configWriter; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->serializer = $this->objectManager->get(\Magento\Framework\Serialize\Serializer\Serialize::class); + $this->cache = $this->objectManager->get(\Magento\Framework\App\CacheInterface::class); + $this->configWriter = $this->objectManager->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); + + $this->initializeMetadataDirectory(); + } + + /** + * Delete compiled file if it was created and clear cache data + */ + protected function tearDown() + { + $compiledPath = \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::getFilePath(self::CACHE_ID); + if (file_exists($compiledPath)) { + unlink($compiledPath); + } + + $this->cache->remove(self::CACHE_ID); + } + + /** + * Test load interception cache from generated/metadata + * @dataProvider interceptionCompiledConfigDataProvider + * @param array $testConfig + */ + public function testInstantiateFromCompiled(array $testConfig) + { + $this->configWriter->write(self::CACHE_ID, $testConfig); + $config = $this->getConfig(); + + foreach ($testConfig as $className => $hasPlugins) { + $this->assertEquals($hasPlugins, $config->hasPlugins($className)); + } + } + + /** + * Test load interception cache from backend cache + * @dataProvider interceptionCacheConfigDataProvider + * @param array $testConfig + */ + public function testInstantiateFromCache(array $testConfig) + { + $this->cache->save($this->serializer->serialize($testConfig), self::CACHE_ID); + $config = $this->getConfig(); + + foreach ($testConfig as $className => $hasPlugins) { + $this->assertEquals($hasPlugins, $config->hasPlugins($className)); + } + } + + public function interceptionCompiledConfigDataProvider() + { + return [ + [['classA' => true, 'classB' => false]], + [['classA' => false, 'classB' => true]], + ]; + } + + public function interceptionCacheConfigDataProvider() + { + return [ + [['classC' => true, 'classD' => false]], + [['classC' => false, 'classD' => true]], + ]; + } + + /** + * Ensure generated/metadata exists + */ + private function initializeMetadataDirectory() + { + $diPath = DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_METADATA][DirectoryList::PATH]; + $fullPath = BP . DIRECTORY_SEPARATOR . $diPath; + if (!file_exists($fullPath)) { + mkdir($fullPath); + } + } + + /** + * Create instance of Config class with specific cacheId. This is done to prevent our test + * from altering the interception config that may have been generated during application + * installation. Inject a new instance of the compileLoaded to bypass it's caching. + * + * @return \Magento\Framework\Interception\Config\Config + */ + private function getConfig() + { + return $this->objectManager->create( + \Magento\Framework\Interception\Config\Config::class, + [ + 'cacheId' => self::CACHE_ID, + 'compiledLoader' => $this->objectManager->create(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class), + ] + ); + } +} From 7dae4c185b01b621cd51841ecb67521d8b745298 Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Wed, 24 Oct 2018 16:39:34 -0400 Subject: [PATCH 0307/1158] Update serializer used in integration test Replace serialize with it's interface. Also passes the serializer when instantiating the test subject. This ensures the correct implementation is used becuase the interface preference and fallback in the constructor do not match. --- .../Magento/Framework/Interception/Config/ConfigTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php index 5221b8bb422cf..1ece9189169bb 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php @@ -38,7 +38,7 @@ protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->serializer = $this->objectManager->get(\Magento\Framework\Serialize\Serializer\Serialize::class); + $this->serializer = $this->objectManager->get(\Magento\Framework\Serialize\SerializerInterface::class); $this->cache = $this->objectManager->get(\Magento\Framework\App\CacheInterface::class); $this->configWriter = $this->objectManager->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); @@ -130,6 +130,7 @@ private function getConfig() [ 'cacheId' => self::CACHE_ID, 'compiledLoader' => $this->objectManager->create(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class), + 'serializer' => $this->serializer, ] ); } From 4eac0fce975759e961793d88c77d35f61bd9d94e Mon Sep 17 00:00:00 2001 From: Ronak Patel <ronak2ram@gmail.com> Date: Fri, 26 Oct 2018 13:06:44 +0530 Subject: [PATCH 0308/1158] Added warning log --- .../Magento/CmsGraphQl/Model/Resolver/Blocks.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php b/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php index d7c0008c7d927..fabb479763e60 100644 --- a/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php +++ b/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php @@ -14,6 +14,7 @@ use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Psr\Log\LoggerInterface; /** * CMS blocks field resolver, used for GraphQL request processing @@ -25,13 +26,20 @@ class Blocks implements ResolverInterface */ private $blockDataProvider; + /** + * @var LoggerInterface + */ + private $logger; + /** * @param BlockDataProvider $blockDataProvider */ public function __construct( - BlockDataProvider $blockDataProvider + BlockDataProvider $blockDataProvider, + LoggerInterface $logger ) { $this->blockDataProvider = $blockDataProvider; + $this->logger = $logger; } /** @@ -81,6 +89,10 @@ private function getBlocksData(array $blockIdentifiers): array $blockData = $this->blockDataProvider->getData($blockIdentifier); if (!empty($blockData)) { $blocksData[$blockIdentifier] = $blockData; + } else { + $this->logger->warning( + sprintf('The CMS block with the "%s" Identifier is disabled.', $blockIdentifier) + ); } } } catch (NoSuchEntityException $e) { From 755ef37b3a1e35b59f38652e69f1c26ea1ff56b4 Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Fri, 26 Oct 2018 12:59:49 +0300 Subject: [PATCH 0309/1158] MAGETWO-95517: Add different types of products on the quote including gift card --- .../Mftf/ActionGroup/AdminProductAttributeActionGroup.xml | 1 - .../Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index c44610ef19649..80cadbb6571f2 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -13,7 +13,6 @@ <argument name="ProductAttribute"/> </arguments> <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" userInput="{{ProductAttribute.attribute_code}}" stepKey="setAttributeCode"/> <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="searchForAttributeFromTheGrid"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml index c21f23d16463e..5be2a84f54555 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml @@ -65,7 +65,7 @@ <data key="is_default">false</data> <data key="sort_order">0</data> </entity> - <entity name="productAttributeOption7" type="ProductAttributeOption"> + <entity name="ProductAttributeOption7" type="ProductAttributeOption"> <var key="attribute_code" entityKey="attribute_code" entityType="ProductAttribute"/> <data key="label" unique="suffix">Green</data> <data key="is_default">false</data> @@ -73,7 +73,7 @@ <requiredEntity type="StoreLabel">Option7Store0</requiredEntity> <requiredEntity type="StoreLabel">Option8Store1</requiredEntity> </entity> - <entity name="productAttributeOption8" type="ProductAttributeOption"> + <entity name="ProductAttributeOption8" type="ProductAttributeOption"> <var key="attribute_code" entityKey="attribute_code" entityType="ProductAttribute"/> <data key="label" unique="suffix">Red</data> <data key="is_default">false</data> From 63cc7536ae1d0a070c047b3b06ad3eb1889b61a7 Mon Sep 17 00:00:00 2001 From: Nikita Shcherbatykh <nikita.shcherbatykh@transoftgroup.com> Date: Fri, 26 Oct 2018 13:22:57 +0300 Subject: [PATCH 0310/1158] MAGETWO-95753: [2.3] Cannot save product with Tier Prices --- app/code/Magento/Catalog/Helper/Data.php | 23 ++-- .../Backend/TierPrice/UpdateHandler.php | 17 ++- .../Controller/Adminhtml/ProductTest.php | 103 ++++++++++++++++++ 3 files changed, 125 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Catalog/Helper/Data.php b/app/code/Magento/Catalog/Helper/Data.php index ae20cda460796..c83eb70486c43 100644 --- a/app/code/Magento/Catalog/Helper/Data.php +++ b/app/code/Magento/Catalog/Helper/Data.php @@ -7,6 +7,7 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Store\Model\ScopeInterface; use Magento\Customer\Model\Session as CustomerSession; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Pricing\PriceCurrencyInterface; @@ -273,7 +274,8 @@ public function setStoreId($store) /** * Return current category path or get it from current category - * and creating array of categories|product paths for breadcrumbs + * + * Creating array of categories|product paths for breadcrumbs * * @return array */ @@ -382,6 +384,7 @@ public function getLastViewedUrl() /** * Split SKU of an item by dashes and spaces + * * Words will not be broken, unless this length is greater than $length * * @param string $sku @@ -410,14 +413,15 @@ public function getAttributeHiddenFields() /** * Retrieve Catalog Price Scope * - * @return int + * @return int/null */ - public function getPriceScope() + public function getPriceScope(): ?int { - return $this->scopeConfig->getValue( + $priceScope = $this->scopeConfig->getValue( self::XML_PATH_PRICE_SCOPE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ScopeInterface::SCOPE_STORE ); + return isset($priceScope) ? (int)$priceScope : null; } /** @@ -439,7 +443,7 @@ public function isUsingStaticUrlsAllowed() { return $this->scopeConfig->isSetFlag( self::CONFIG_USE_STATIC_URLS, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ScopeInterface::SCOPE_STORE ); } @@ -454,7 +458,7 @@ public function isUrlDirectivesParsingAllowed() { return $this->scopeConfig->isSetFlag( self::CONFIG_PARSE_URL_DIRECTIVES, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORE, $this->_storeId ); } @@ -472,6 +476,7 @@ public function getPageTemplateProcessor() /** * Whether to display items count for each filter option + * * @param int $storeId Store view ID * @return bool */ @@ -479,12 +484,14 @@ public function shouldDisplayProductCountOnLayer($storeId = null) { return $this->scopeConfig->isSetFlag( self::XML_PATH_DISPLAY_PRODUCT_COUNT, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORE, $storeId ); } /** + * Convert tax address array to address data object with country id and postcode + * * @param array $taxAddress * @return \Magento\Customer\Api\Data\AddressInterface|null */ diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php index b4d6dc2c19e51..aef3e87586015 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php @@ -86,10 +86,10 @@ public function execute($entity, $arguments = []) __('Tier prices data should be array, but actually other type is received') ); } - $websiteId = $this->storeManager->getStore($entity->getStoreId())->getWebsiteId(); + $websiteId = (int)$this->storeManager->getStore($entity->getStoreId())->getWebsiteId(); $isGlobal = $attribute->isScopeGlobal() || $websiteId === 0; $identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField(); - $productId = (int) $entity->getData($identifierField); + $productId = (int)$entity->getData($identifierField); // prepare original data to compare $origPrices = []; @@ -98,7 +98,7 @@ public function execute($entity, $arguments = []) $origPrices = $entity->getOrigData($attribute->getName()); } - $old = $this->prepareOriginalDataToCompare($origPrices, $isGlobal); + $old = $this->prepareOldTierPriceToCompare($origPrices); // prepare data for save $new = $this->prepareNewDataForSave($priceRows, $isGlobal); @@ -271,21 +271,18 @@ private function isWebsiteGlobal(int $websiteId): bool } /** - * Prepare original data to compare. + * Prepare old data to compare. * * @param array|null $origPrices - * @param bool $isGlobal * @return array */ - private function prepareOriginalDataToCompare(?array $origPrices, bool $isGlobal = true): array + private function prepareOldTierPriceToCompare(?array $origPrices): array { $old = []; if (is_array($origPrices)) { foreach ($origPrices as $data) { - if ($isGlobal === $this->isWebsiteGlobal((int)$data['website_id'])) { - $key = $this->getPriceKey($data); - $old[$key] = $data; - } + $key = $this->getPriceKey($data); + $old[$key] = $data; } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php index 06bbc43e36e8d..d949993e7ea3c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php @@ -252,4 +252,107 @@ public function saveActionWithAlreadyExistingUrlKeyDataProvider() ] ]; } + + /** + * Test product save with selected tier price + * + * @dataProvider saveActionTierPriceDataProvider + * @param array $postData + * @param array $tierPrice + * @magentoDataFixture Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php + * @magentoAppIsolation enabled + * @magentoConfigFixture current_store catalog/price/scope 1 + * @magentoDbIsolation disabled + */ + public function testSaveActionTierPrice(array $postData, array $tierPrice) + { + $postData['product'] = $this->getProductData($tierPrice); + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue($postData); + $this->dispatch('backend/catalog/product/save/id/' . $postData['id']); + $this->assertSessionMessages( + $this->contains('You saved the product.'), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + } + + /** + * Provide test data for testSaveActionWithAlreadyExistingUrlKey(). + * + * @return array + */ + public function saveActionTierPriceDataProvider() + { + return [ + [ + 'post_data' => [ + 'id' => '1', + 'type' => 'simple', + 'store' => '0', + 'set' => '4', + 'back' => 'edit', + 'product' => [], + 'is_downloadable' => '0', + 'affect_configurable_product_attributes' => '1', + 'new_variation_attribute_set_id' => '4', + 'use_default' => [ + 'gift_message_available' => '0', + 'gift_wrapping_available' => '0' + ], + 'configurable_matrix_serialized' => '[]', + 'associated_product_ids_serialized' => '[]' + ], + 'tier_price_for_request' => [ + [ + 'price_id' => '1', + 'website_id' => '0', + 'cust_group' => '32000', + 'price' => '111.00', + 'price_qty' => '100', + 'website_price' => '111.0000', + 'initialize' => 'true', + 'record_id' => '1', + 'value_type' => 'fixed' + ], + [ + 'price_id' => '2', + 'website_id' => '1', + 'cust_group' => '32000', + 'price' => '222.00', + 'price_qty' => '200', + 'website_price' => '111.0000', + 'initialize' => 'true', + 'record_id' => '2', + 'value_type' => 'fixed' + ], + [ + 'price_id' => '3', + 'website_id' => '1', + 'cust_group' => '32000', + 'price' => '333.00', + 'price_qty' => '300', + 'website_price' => '111.0000', + 'initialize' => 'true', + 'record_id' => '3', + 'value_type' => 'fixed' + ] + ] + ] + ]; + } + + /** + * Return product data for test without entity_id for further save + * + * @param array $tierPrice + * @return array + */ + private function getProductData(array $tierPrice) + { + $repository = $this->_objectManager->create(\Magento\Catalog\Model\ProductRepository::class); + $product = $repository->get('tier_prices')->getData(); + $product['tier_price'] = $tierPrice; + unset($product['entity_id']); + return $product; + } } From c8eb11567542d5e8002180801153fa19f6724336 Mon Sep 17 00:00:00 2001 From: David Verholen <david@verholen.com> Date: Fri, 26 Oct 2018 12:42:07 +0200 Subject: [PATCH 0311/1158] GraphQL-43: introduce wishlist graphql module --- .../WishlistItemsProductsResolver.php | 58 ++++++++++++++++++ .../Model/Resolver/WishlistItemsResolver.php | 60 +++++++++++++++++++ .../Model/Resolver/WishlistResolver.php | 55 +++++++++++++++++ .../Model/WishlistDataProvider.php | 39 ++++++++++++ .../Model/WishlistItemsDataProvider.php | 52 ++++++++++++++++ .../WishlistItemsProductDataProvider.php | 32 ++++++++++ app/code/Magento/WishlistGraphQl/README.md | 4 ++ .../Magento/WishlistGraphQl/composer.json | 25 ++++++++ .../Magento/WishlistGraphQl/etc/module.xml | 10 ++++ .../WishlistGraphQl/etc/schema.graphqls | 20 +++++++ .../Magento/WishlistGraphQl/registration.php | 9 +++ composer.json | 1 + 12 files changed, 365 insertions(+) create mode 100644 app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php create mode 100644 app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php create mode 100644 app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php create mode 100644 app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php create mode 100644 app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php create mode 100644 app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php create mode 100644 app/code/Magento/WishlistGraphQl/README.md create mode 100644 app/code/Magento/WishlistGraphQl/composer.json create mode 100644 app/code/Magento/WishlistGraphQl/etc/module.xml create mode 100644 app/code/Magento/WishlistGraphQl/etc/schema.graphqls create mode 100644 app/code/Magento/WishlistGraphQl/registration.php diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php new file mode 100644 index 0000000000000..567e85c3c0309 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php @@ -0,0 +1,58 @@ +<?php +declare(strict_types=1); +/** + * WishlistItemsProductsResolver + * + * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. + * @author david.verholen@brandung.de + */ + +namespace Magento\WishlistGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Framework\GraphQl\Query\Resolver\Value; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\WishlistGraphQl\Model\WishlistItemsProductDataProvider; + +class WishlistItemsProductsResolver implements ResolverInterface +{ + /** + * @var WishlistItemsProductDataProvider + */ + private $productDataProvider; + + public function __construct(WishlistItemsProductDataProvider $productDataProvider) + { + $this->productDataProvider = $productDataProvider; + } + + + /** + * Fetches the data from persistence models and format it according to the GraphQL schema. + * + * @param \Magento\Framework\GraphQl\Config\Element\Field $field + * @param ContextInterface $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * @throws \Exception + * @return mixed|Value + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (!isset($value['product_id'])) { + throw new GraphQlInputException( + __('Missing key %1 in wishlist item data', ['product_id']) + ); + } + return $this->productDataProvider->getProductDataById($value['product_id']); + } +} diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php new file mode 100644 index 0000000000000..3f51db6eef3e1 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php @@ -0,0 +1,60 @@ +<?php +declare(strict_types=1); +/** + * WishlistItemTypeResolver + * + * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. + * @author david.verholen@brandung.de + */ + +namespace Magento\WishlistGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Framework\GraphQl\Query\Resolver\Value; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Wishlist\Model\Item; +use Magento\WishlistGraphQl\Model\WishlistItemsDataProvider; + +class WishlistItemsResolver implements ResolverInterface +{ + /** + * @var WishlistItemsDataProvider + */ + private $wishlistItemsDataProvider; + + public function __construct(WishlistItemsDataProvider $wishlistItemsDataProvider) + { + $this->wishlistItemsDataProvider = $wishlistItemsDataProvider; + } + + /** + * Fetches the data from persistence models and format it according to the GraphQL schema. + * + * @param \Magento\Framework\GraphQl\Config\Element\Field $field + * @param ContextInterface $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * @throws \Exception + * @return mixed|Value + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + return array_map(function (Item $wishlistItem) { + return [ + 'id' => $wishlistItem->getId(), + 'qty' => $wishlistItem->getData('qty'), + 'description' => (string)$wishlistItem->getDescription(), + 'added_at' => $wishlistItem->getAddedAt(), + 'product_id' => (int)$wishlistItem->getProductId() + ]; + }, $this->wishlistItemsDataProvider->getWishlistItemsForCustomer($context->getUserId())); + } +} diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php new file mode 100644 index 0000000000000..3aec792b9de54 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php @@ -0,0 +1,55 @@ +<?php +declare(strict_types=1); +/** + * WishlistItemTypeResolver + * + * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. + * @author david.verholen@brandung.de + */ + +namespace Magento\WishlistGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Framework\GraphQl\Query\Resolver\Value; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\WishlistGraphQl\Model\WishlistDataProvider; + +class WishlistResolver implements ResolverInterface +{ + /** + * @var WishlistDataProvider + */ + private $wishlistDataProvider; + + public function __construct(WishlistDataProvider $wishlistDataProvider) + { + $this->wishlistDataProvider = $wishlistDataProvider; + } + + /** + * Fetches the data from persistence models and format it according to the GraphQL schema. + * + * @param \Magento\Framework\GraphQl\Config\Element\Field $field + * @param ContextInterface $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * @throws \Exception + * @return mixed|Value + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + $wishlist = $this->wishlistDataProvider->getWishlistForCustomer($context->getUserId()); + return [ + 'sharing_code' => $wishlist->getSharingCode(), + 'updated_at' => $wishlist->getUpdatedAt() + ]; + } +} diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php new file mode 100644 index 0000000000000..8f472d610ff4c --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php @@ -0,0 +1,39 @@ +<?php +declare(strict_types=1); +/** + * WishlistItemTypeResolver + * + * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. + * @author david.verholen@brandung.de + */ + +namespace Magento\WishlistGraphQl\Model; + +use Magento\Wishlist\Model\ResourceModel\Wishlist; +use Magento\Wishlist\Model\WishlistFactory; + +class WishlistDataProvider +{ + /** + * @var Wishlist + */ + private $wishlistResource; + /** + * @var WishlistFactory + */ + private $wishlistFactory; + + public function __construct(Wishlist $wishlistResource, WishlistFactory $wishlistFactory) + { + $this->wishlistResource = $wishlistResource; + $this->wishlistFactory = $wishlistFactory; + } + + public function getWishlistForCustomer(int $customerId): \Magento\Wishlist\Model\Wishlist + { + /** @var \Magento\Wishlist\Model\Wishlist $wishlist */ + $wishlist = $this->wishlistFactory->create(); + $this->wishlistResource->load($wishlist, $customerId, 'customer_id'); + return $wishlist; + } +} diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php new file mode 100644 index 0000000000000..e339b4886a942 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php @@ -0,0 +1,52 @@ +<?php +declare(strict_types=1); +/** + * WishlistItemTypeResolver + * + * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. + * @author david.verholen@brandung.de + */ + +namespace Magento\WishlistGraphQl\Model; + +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Wishlist\Model\Item; +use Magento\Wishlist\Model\ResourceModel\Item\CollectionFactory as WishlistItemCollectionFactory; + +class WishlistItemsDataProvider +{ + + /** + * @var WishlistItemCollectionFactory + */ + private $wishlistItemCollectionFactory; + /** + * @var StoreManagerInterface + */ + private $storeManager; + + public function __construct( + WishlistItemCollectionFactory $wishlistItemCollectionFactory, + StoreManagerInterface $storeManager + ) { + $this->wishlistItemCollectionFactory = $wishlistItemCollectionFactory; + $this->storeManager = $storeManager; + } + + /** + * @param int $customerId + * @return Item[] + */ + public function getWishlistItemsForCustomer(int $customerId): array + { + $wishlistItemCollection = $this->wishlistItemCollectionFactory->create(); + $wishlistItemCollection->addCustomerIdFilter($customerId); + $wishlistItemCollection->addStoreFilter(array_map(function (StoreInterface $store) { + return $store->getId(); + }, $this->storeManager->getStores())); + $wishlistItemCollection->setVisibilityFilter(); + $wishlistItemCollection->load(); + return $wishlistItemCollection->getItems(); + } +} diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php new file mode 100644 index 0000000000000..a9aa5dc184397 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php @@ -0,0 +1,32 @@ +<?php +declare(strict_types=1); +/** + * WishlistItemsProductsResolver + * + * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. + * @author david.verholen@brandung.de + */ + +namespace Magento\WishlistGraphQl\Model; + +use Magento\Catalog\Api\ProductRepositoryInterface; + +class WishlistItemsProductDataProvider +{ + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + public function __construct(ProductRepositoryInterface $productRepository) + { + $this->productRepository = $productRepository; + } + + public function getProductDataById(int $productId) { + $product = $this->productRepository->getById($productId); + $productData = $product->toArray(); + $productData['model'] = $product; + return $productData; + } +} diff --git a/app/code/Magento/WishlistGraphQl/README.md b/app/code/Magento/WishlistGraphQl/README.md new file mode 100644 index 0000000000000..9121593e6a759 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/README.md @@ -0,0 +1,4 @@ +# WishlistGraphQl + +**WishlistGraphQl** provides type information for the GraphQl module +to generate wishlist fields. diff --git a/app/code/Magento/WishlistGraphQl/composer.json b/app/code/Magento/WishlistGraphQl/composer.json new file mode 100644 index 0000000000000..2be27d4239f73 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/composer.json @@ -0,0 +1,25 @@ +{ + "name": "magento/module-wishlist-graph-ql", + "description": "N/A", + "type": "magento2-module", + "require": { + "php": "~7.1.3||~7.2.0", + "magento/framework": "*", + "magento/module-catalog": "*" + }, + "suggest": { + "magento/module-wishlist": "*" + }, + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\WishlistGraphQl\\": "" + } + } +} diff --git a/app/code/Magento/WishlistGraphQl/etc/module.xml b/app/code/Magento/WishlistGraphQl/etc/module.xml new file mode 100644 index 0000000000000..337623cc85a92 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_WishlistGraphQl" /> +</config> diff --git a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls new file mode 100644 index 0000000000000..5c6d701138560 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls @@ -0,0 +1,20 @@ +# Copyright © Magento, Inc. All rights reserved. +# See COPYING.txt for license details. + +type Query { + wishlist: WishlistOutput @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistResolver") @doc(description: "todo") +} + +type WishlistOutput { + items: [WishlistItem] @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsResolver") @doc(description: "todo"), + sharing_code: String! @doc(description: "todo"), + updated_at: String! @doc(description: "todo") +} + +type WishlistItem { + id: Int! @doc(description: "todo") + qty: Float! @doc(description: "todo"), + description: String! @doc(description: "todo"), + added_at: String! @doc(description: "todo"), + product: ProductInterface @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsProductsResolver") +} \ No newline at end of file diff --git a/app/code/Magento/WishlistGraphQl/registration.php b/app/code/Magento/WishlistGraphQl/registration.php new file mode 100644 index 0000000000000..f2047f225e5b6 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/registration.php @@ -0,0 +1,9 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_WishlistGraphQl', __DIR__); diff --git a/composer.json b/composer.json index 3f8f0a033c893..eede85d273777 100644 --- a/composer.json +++ b/composer.json @@ -237,6 +237,7 @@ "magento/module-weee": "*", "magento/module-widget": "*", "magento/module-wishlist": "*", + "magento/module-wishlist-graph-ql": "*", "magento/module-wishlist-analytics": "*", "magento/theme-adminhtml-backend": "*", "magento/theme-frontend-blank": "*", From 0286f170c6e4c74d2e68a11c3de5f588710143fe Mon Sep 17 00:00:00 2001 From: David Verholen <david@verholen.com> Date: Fri, 26 Oct 2018 13:35:10 +0200 Subject: [PATCH 0312/1158] GraphQL-43: add missing hard dependencies --- app/code/Magento/WishlistGraphQl/composer.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/WishlistGraphQl/composer.json b/app/code/Magento/WishlistGraphQl/composer.json index 2be27d4239f73..9226ea1754e6a 100644 --- a/app/code/Magento/WishlistGraphQl/composer.json +++ b/app/code/Magento/WishlistGraphQl/composer.json @@ -5,10 +5,9 @@ "require": { "php": "~7.1.3||~7.2.0", "magento/framework": "*", - "magento/module-catalog": "*" - }, - "suggest": { - "magento/module-wishlist": "*" + "magento/module-catalog": "*", + "magento/module-wishlist": "*", + "magento/module-store": "*" }, "license": [ "OSL-3.0", From 98715ca4060c262d90f48e31c1f1d202bd2d23b5 Mon Sep 17 00:00:00 2001 From: stani <sa@webvisum.de> Date: Fri, 26 Oct 2018 13:16:58 +0200 Subject: [PATCH 0313/1158] magento-engcom/import-export-improvements#93: show errors and link to download csv error report on success page --- .../Controller/Adminhtml/Import/Start.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php index 8f64d023c19f9..06b69c512a194 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php @@ -93,6 +93,20 @@ public function execute() $this->addErrorMessages($resultBlock, $errorAggregator); } else { $this->importModel->invalidateIndex(); + + $noticeHtml = $this->historyModel->getSummary(); + + if($this->historyModel->getErrorFile()) { + $noticeHtml .= '<div class="import-error-wrapper">' . __('Only the first 100 errors are shown. ') + . '<a href="' + . $this->createDownloadUrlImportHistoryFile($this->historyModel->getErrorFile()) + . '">' . __('Download full report') . '</a></div>'; + } + + $resultBlock->addNotice( + $noticeHtml + ); + $this->addErrorMessages($resultBlock, $errorAggregator); $resultBlock->addSuccess(__('Import successfully done')); } From 2e4ea72289c28a223354b18b399e28843267e538 Mon Sep 17 00:00:00 2001 From: David Verholen <david@verholen.com> Date: Fri, 26 Oct 2018 14:14:25 +0200 Subject: [PATCH 0314/1158] GraphQL-43: add test to retrieve wishlist --- .../Magento/GraphQl/Wishlist/WishlistTest.php | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php new file mode 100644 index 0000000000000..53577d02df50f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Wishlist; + +use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\TestFramework\TestCase\GraphQlAbstract; +use Magento\Wishlist\Model\Item; + +class WishlistTest extends GraphQlAbstract +{ + /** + * @var \Magento\TestFramework\ObjectManager + */ + private $objectManager; + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->customerTokenService = $this->objectManager->get(CustomerTokenServiceInterface::class); + } + + /** + * Verify the fields of CMS Block selected by identifiers + * + * @magentoApiDataFixture Magento/Wishlist/_files/wishlist.php + * @throws \Magento\Framework\Exception\AuthenticationException + * @throws \Exception + */ + public function testGetCustomersWishlist(): void + { + /** @var \Magento\Wishlist\Model\Wishlist $wishlist */ + $wishlist = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Wishlist\Model\Wishlist::class + ); + $wishlist->loadByCustomerId(1, true); + /** @var Item $wishlistItem */ + $wishlistItem = $wishlist->getItemCollection()->getFirstItem(); + $wishlistItemProduct = $wishlistItem->getProduct(); + $query = + <<<QUERY +{ + wishlist { + items { + id + qty + product { + sku + name + } + description + added_at + } + sharing_code + updated_at + } +} +QUERY; + + $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders('customer@example.com', 'password')); + $this->assertEquals($wishlist->getSharingCode(), $response['wishlist']['sharing_code']); + $this->assertEquals($wishlistItem->getData('qty'), $response['wishlist']['items'][0]['qty']); + $this->assertEquals($wishlistItem->getDescription(), $response['wishlist']['items'][0]['description']); + $this->assertEquals($wishlistItemProduct->getSku(), $response['wishlist']['items'][0]['product']['sku']); + $this->assertEquals($wishlistItemProduct->getName(), $response['wishlist']['items'][0]['product']['name']); + } + + /** + * @param string $email + * @param string $password + * @return array + * @throws \Magento\Framework\Exception\AuthenticationException + */ + private function getCustomerAuthHeaders(string $email, string $password): array + { + $customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password); + return ['Authorization' => 'Bearer ' . $customerToken]; + } +} From 89eb2776be3bdacf84a86367d866b8746452f129 Mon Sep 17 00:00:00 2001 From: David Verholen <david@verholen.com> Date: Fri, 26 Oct 2018 14:19:15 +0200 Subject: [PATCH 0315/1158] GraphQL-43: use correct copyright headers in introduced php classes --- .../Model/Resolver/WishlistItemsProductsResolver.php | 8 +++----- .../Model/Resolver/WishlistItemsResolver.php | 8 +++----- .../WishlistGraphQl/Model/Resolver/WishlistResolver.php | 8 +++----- .../WishlistGraphQl/Model/WishlistDataProvider.php | 8 +++----- .../WishlistGraphQl/Model/WishlistItemsDataProvider.php | 8 +++----- .../Model/WishlistItemsProductDataProvider.php | 8 +++----- 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php index 567e85c3c0309..26ace0e849e3f 100644 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php @@ -1,11 +1,9 @@ <?php -declare(strict_types=1); /** - * WishlistItemsProductsResolver - * - * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. - * @author david.verholen@brandung.de + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\WishlistGraphQl\Model\Resolver; diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php index 3f51db6eef3e1..707618b10602d 100644 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php @@ -1,11 +1,9 @@ <?php -declare(strict_types=1); /** - * WishlistItemTypeResolver - * - * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. - * @author david.verholen@brandung.de + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\WishlistGraphQl\Model\Resolver; diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php index 3aec792b9de54..ba1a6e935c10e 100644 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php @@ -1,11 +1,9 @@ <?php -declare(strict_types=1); /** - * WishlistItemTypeResolver - * - * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. - * @author david.verholen@brandung.de + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\WishlistGraphQl\Model\Resolver; diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php index 8f472d610ff4c..a62ddebd91120 100644 --- a/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php +++ b/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php @@ -1,11 +1,9 @@ <?php -declare(strict_types=1); /** - * WishlistItemTypeResolver - * - * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. - * @author david.verholen@brandung.de + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\WishlistGraphQl\Model; diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php index e339b4886a942..ca87b23460fc7 100644 --- a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php +++ b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php @@ -1,11 +1,9 @@ <?php -declare(strict_types=1); /** - * WishlistItemTypeResolver - * - * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. - * @author david.verholen@brandung.de + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\WishlistGraphQl\Model; diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php index a9aa5dc184397..76df065a80702 100644 --- a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php +++ b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php @@ -1,11 +1,9 @@ <?php -declare(strict_types=1); /** - * WishlistItemsProductsResolver - * - * @copyright Copyright © 2018 brandung GmbH & Co. KG. All rights reserved. - * @author david.verholen@brandung.de + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\WishlistGraphQl\Model; From e5e58325500ef7d6df7dd7d928f25a33962f9d69 Mon Sep 17 00:00:00 2001 From: stani <sa@webvisum.de> Date: Fri, 26 Oct 2018 14:42:26 +0200 Subject: [PATCH 0316/1158] magento-engcom/import-export-improvements#54: function getBehavior extended with BEHAVIOUR_ADD_UPDATE and BEHAVIOR_CUSTOM --- .../Magento/ImportExport/Model/Import/Entity/AbstractEntity.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php index e965e8ad207fd..74e2c5626236c 100644 --- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php +++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php @@ -554,7 +554,9 @@ public function getBehavior() $this->_parameters['behavior'] ) || $this->_parameters['behavior'] != ImportExport::BEHAVIOR_APPEND && + $this->_parameters['behavior'] != ImportExport::BEHAVIOR_ADD_UPDATE && $this->_parameters['behavior'] != ImportExport::BEHAVIOR_REPLACE && + $this->_parameters['behavior'] != ImportExport::BEHAVIOR_CUSTOM && $this->_parameters['behavior'] != ImportExport::BEHAVIOR_DELETE ) { return ImportExport::getDefaultBehavior(); From b25c01f70567e86ab3d2a6ed63faa37362b8ab00 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Fri, 26 Oct 2018 16:12:59 +0300 Subject: [PATCH 0317/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page --- .../Adminhtml/Edit/Address/CancelButton.php | 41 + .../Adminhtml/Edit/Address/DeleteButton.php | 52 + .../Adminhtml/Edit/Address/GenericButton.php | 110 ++ .../Adminhtml/Edit/Address/SaveButton.php | 33 + .../Address/AbstractDefaultAddress.php | 99 ++ .../Address/DefaultBillingAddress.php | 39 + .../Address/DefaultShippingAddress.php | 39 + .../Controller/Adminhtml/Address/Delete.php | 65 + .../Adminhtml/Address/MassDelete.php | 87 ++ .../Controller/Adminhtml/Address/Save.php | 149 +++ .../Controller/Adminhtml/Address/Validate.php | 97 ++ .../Adminhtml/File/Address/Upload.php | 28 +- .../Controller/Adminhtml/Index/Save.php | 21 +- .../Controller/Adminhtml/Index/Validate.php | 39 +- .../Customer/Model/Address/DataProvider.php | 574 +++++++++ .../DataProviderWithDefaultAddresses.php | 585 +++++++++ .../Customer/Model/Metadata/Form/File.php | 2 +- .../ResourceModel/Address/Grid/Collection.php | 171 +++ .../Model/ResourceModel/Address/Relation.php | 15 +- .../ResourceModel/CustomerRepository.php | 54 +- .../Test/Unit/Controller/Address/SaveTest.php | 205 ++++ .../Unit/Controller/Address/ValidateTest.php | 118 ++ .../Controller/Adminhtml/Index/SaveTest.php | 226 +--- .../Adminhtml/Index/ValidateTest.php | 28 - .../Unit/Model/Address/DataProviderTest.php | 233 ++++ .../DataProviderWithDefaultAddressesTest.php | 1065 +++++++++++++++++ .../ResourceModel/CustomerRepositoryTest.php | 126 -- .../Ui/Component/Form/AddressFieldsetTest.php | 69 ++ .../Ui/Component/Form/AddressFieldset.php | 45 + .../Listing/Address/Column/Actions.php | 134 +++ .../Listing/Address/Column/Countries.php | 37 + app/code/Magento/Customer/etc/db_schema.xml | 9 + app/code/Magento/Customer/etc/di.xml | 9 + .../layout/customer_address_edit.xml | 15 + .../ui_component/customer_address_form.xml | 230 ++++ .../ui_component/customer_address_listing.xml | 171 +++ .../web/js/address/default-address-block.js | 17 + .../web/js/address/default-address.js | 44 + .../view/adminhtml/web/js/address/modal.js | 203 ++++ .../web/js/form/components/insert-form.js | 164 +++ .../web/template/default-address.html | 42 + .../view/base/ui_component/customer_form.xml | 357 +++--- .../Component/Form/Element/DataType/Media.php | 1 + .../Magento/Ui/Component/Form/Fieldset.php | 14 +- app/code/Magento/Ui/Component/Layout/Tabs.php | 4 + .../Test/Unit/Component/Form/FieldsetTest.php | 69 ++ .../base/web/js/form/components/collection.js | 7 +- .../web/js/form/components/collection/item.js | 5 +- .../view/base/web/templates/form/insert.html | 3 - .../web/css/source/_module.less | 72 +- .../Controller/Adminhtml/Address/SaveTest.php | 222 ++++ .../Test/Php/_files/blacklist/strict_type.txt | 2 +- .../config/customerConfig.xml | 2 +- 53 files changed, 5529 insertions(+), 719 deletions(-) create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php create mode 100644 app/code/Magento/Customer/Model/Address/DataProvider.php create mode 100644 app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php create mode 100644 app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php create mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php create mode 100644 app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php create mode 100644 app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php create mode 100644 app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php create mode 100644 app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml create mode 100644 app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml create mode 100644 app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/template/default-address.html create mode 100644 app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php new file mode 100644 index 0000000000000..80d9780f819d0 --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; +use Magento\Customer\Block\Adminhtml\Edit\GenericButton; + +/** + * Class CancelButton + */ +class CancelButton extends GenericButton implements ButtonProviderInterface +{ + /** + * {@inheritdoc} + * + * @return array + */ + public function getButtonData() + { + return [ + 'label' => __('Cancel'), + 'on_click' => '', + 'data_attribute' => [ + 'mage-init' => [ + 'Magento_Ui/js/form/button-adapter' => [ + 'actions' => [ + [ + 'targetName' => 'customer_form.areas.address.address.customer_address_update_modal', + 'actionName' => 'closeModal' + ], + ], + ], + ], + ], + 'sort_order' => 20 + ]; + } +} diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php new file mode 100644 index 0000000000000..8375aa13fdeff --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -0,0 +1,52 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; +use Magento\Customer\Ui\Component\Listing\Address\Column\Actions; + +/** + * Delete button on edit customer address form + */ +class DeleteButton extends GenericButton implements ButtonProviderInterface +{ + /** + * Get delete button data. + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getButtonData() + { + $data = []; + if ($this->getAddressId()) { + $data = [ + 'label' => __('Delete'), + 'class' => 'delete', + 'on_click' => 'deleteConfirm(\'' . __( + 'Are you sure you want to delete this address?' + ) . '\', \'' . $this->getDeleteUrl() . '\')', + 'sort_order' => 15, + ]; + } + return $data; + } + + /** + * Get delete button url. + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getDeleteUrl(): string + { + return $this->getUrl( + Actions::CUSTOMER_ADDRESS_PATH_DELETE, + ['parent_id' => $this->getCustomerId(), 'id' => $this->getAddressId()] + ); + } +} diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php new file mode 100644 index 0000000000000..ae09ee6896891 --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php @@ -0,0 +1,110 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Customer\Model\AddressFactory; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\UrlInterface; +use Magento\Customer\Model\ResourceModel\Address; +use Magento\Customer\Model\ResourceModel\AddressRepository; + +/** + * Class for common code for buttons on the create/edit address form + */ +class GenericButton +{ + /** + * @var AddressFactory + */ + private $addressFactory; + + /** + * @var UrlInterface + */ + private $urlBuilder; + + /** + * @var Address + */ + private $addressResourceModel; + + /** + * @var RequestInterface + */ + private $request; + + /** + * @var AddressRepository + */ + private $addressRepository; + + /** + * @param AddressFactory $addressFactory + * @param UrlInterface $urlBuilder + * @param Address $addressResourceModel + * @param RequestInterface $request + * @param AddressRepository $addressRepository + */ + public function __construct( + AddressFactory $addressFactory, + UrlInterface $urlBuilder, + Address $addressResourceModel, + RequestInterface $request, + AddressRepository $addressRepository + ) { + $this->addressFactory = $addressFactory; + $this->urlBuilder = $urlBuilder; + $this->addressResourceModel = $addressResourceModel; + $this->request = $request; + $this->addressRepository = $addressRepository; + } + + /** + * Return address Id. + * + * @return int|null + */ + public function getAddressId() + { + $address = $this->addressFactory->create(); + + $entityId = $this->request->getParam('entity_id'); + $this->addressResourceModel->load( + $address, + $entityId + ); + + return $address->getEntityId() ?: null; + } + + /** + * Get customer id. + * + * @return int|null + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getCustomerId() + { + $addressId = $this->request->getParam('entity_id'); + + $address = $this->addressRepository->getById($addressId); + + return $address->getCustomerId() ?: null; + } + + /** + * Generate url by route and parameters + * + * @param string $route + * @param array $params + * @return string + */ + public function getUrl($route = '', array $params = []): string + { + return $this->urlBuilder->getUrl($route, $params); + } +} diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php new file mode 100644 index 0000000000000..706ef32c9e5a5 --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; +use Magento\Customer\Block\Adminhtml\Edit\GenericButton; + +/** + * Class SaveButton + */ +class SaveButton extends GenericButton implements ButtonProviderInterface +{ + /** + * {@inheritdoc} + * + * @return array + */ + public function getButtonData() + { + return [ + 'label' => __('Save'), + 'class' => 'save primary', + 'data_attribute' => [ + 'mage-init' => ['button' => ['event' => 'save']], + 'form-role' => 'save', + ], + 'sort_order' => 10 + ]; + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php new file mode 100644 index 0000000000000..a2f9d12282188 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -0,0 +1,99 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\Phrase; +use Psr\Log\LoggerInterface; + +/** + * Abstract class for customer default addresses changing + */ +abstract class AbstractDefaultAddress extends Action +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param Action\Context $context + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param LoggerInterface $logger + */ + public function __construct( + Action\Context $context, + \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, + LoggerInterface $logger + ) { + parent::__construct($context); + $this->addressRepository = $addressRepository; + $this->logger = $logger; + } + + /** + * Execute action to change customer default address + * + * @return \Magento\Framework\Controller\Result\Redirect + */ + public function execute(): Redirect + { + $customerId = $this->getRequest()->getParam('parent_id', false); + $addressId = $this->getRequest()->getParam('id', false); + if ($addressId) { + try { + $address = $this->addressRepository->getById($addressId)->setCustomerId($customerId); + $this->setAddressAsDefault($address); + $this->addressRepository->save($address); + + $this->messageManager->addSuccessMessage($this->getSuccessMessage()); + } catch (\Exception $other) { + $this->logger->critical($other); + $this->messageManager->addExceptionMessage($other, $this->getExceptionMessage()); + } + } + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + + return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + } + + /** + * Set passed address as customer's default address + * + * @param \Magento\Customer\Api\Data\AddressInterface $address + * @return $this + */ + abstract protected function setAddressAsDefault($address); + + /** + * Get success message about default address changed + * + * @return \Magento\Framework\Phrase + */ + abstract protected function getSuccessMessage(): Phrase; + + /** + * Get error message about unsuccessful attempt to change default address + * + * @return \Magento\Framework\Phrase + */ + abstract protected function getExceptionMessage(): Phrase; +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php new file mode 100644 index 0000000000000..bd921a5a6642e --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php @@ -0,0 +1,39 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Framework\Phrase; + +/** + * Class to process default billing address setting + */ +class DefaultBillingAddress extends AbstractDefaultAddress +{ + /** + * @inheritdoc + */ + protected function setAddressAsDefault($address) + { + $address->setIsDefaultBilling(true); + } + + /** + * @inheritdoc + */ + protected function getSuccessMessage(): Phrase + { + return __('Default billing address has been changed.'); + } + + /** + * @inheritdoc + */ + protected function getExceptionMessage(): Phrase + { + return __('We can\'t change default billing address right now.'); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php new file mode 100644 index 0000000000000..7d5bef9ab5be9 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php @@ -0,0 +1,39 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Framework\Phrase; + +/** + * Class to process default shipping address setting + */ +class DefaultShippingAddress extends AbstractDefaultAddress +{ + /** + * @inheritdoc + */ + protected function setAddressAsDefault($address) + { + $address->setIsDefaultShipping(true); + } + + /** + * @inheritdoc + */ + protected function getSuccessMessage(): Phrase + { + return __('Default shipping address has been changed.'); + } + + /** + * @inheritdoc + */ + protected function getExceptionMessage(): Phrase + { + return __('We can\'t change default shipping address right now.'); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php new file mode 100644 index 0000000000000..8443c777546f6 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -0,0 +1,65 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Redirect; +use Magento\Customer\Api\AddressRepositoryInterface; + +/** + * Button for deletion of customer address in admin * + */ +class Delete extends Action +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @param Action\Context $context + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + */ + public function __construct( + Action\Context $context, + AddressRepositoryInterface $addressRepository + ) { + parent::__construct($context); + $this->addressRepository = $addressRepository; + } + + /** + * Delete action + * + * @return \Magento\Framework\Controller\Result\Redirect + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function execute(): Redirect + { + $customerId = $this->getRequest()->getParam('parent_id', false); + $addressId = $this->getRequest()->getParam('id', false); + if ($addressId && $this->addressRepository->getById($addressId)->getCustomerId() === $customerId) { + try { + $this->addressRepository->deleteById($addressId); + $this->messageManager->addSuccessMessage(__('You deleted the address.')); + } catch (\Exception $other) { + $this->messageManager->addExceptionMessage($other, __('We can\'t delete the address right now.')); + } + } + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + + return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php new file mode 100644 index 0000000000000..f022ea36f420d --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Framework\Controller\ResultFactory; +use Magento\Backend\App\Action\Context; +use Magento\Ui\Component\MassAction\Filter; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Customer\Api\AddressRepositoryInterface; + +/** + * Class to delete selected customer addresses through massaction + */ +class MassDelete extends \Magento\Backend\App\Action +{ + /** + * Authorization level of a basic admin session + * + * @see MassDelete::_isAllowed() + */ + const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var Filter + */ + protected $filter; + + /** + * @var CollectionFactory + */ + protected $collectionFactory; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @param Context $context + * @param Filter $filter + * @param CollectionFactory $collectionFactory + * @param AddressRepositoryInterface $addressRepository + */ + public function __construct( + Context $context, + Filter $filter, + CollectionFactory $collectionFactory, + AddressRepositoryInterface $addressRepository + ) { + $this->filter = $filter; + $this->collectionFactory = $collectionFactory; + $this->addressRepository = $addressRepository; + parent::__construct($context); + } + + /** + * Execute action + * + * @return \Magento\Backend\Model\View\Result\Redirect + * @throws \Magento\Framework\Exception\LocalizedException|\Exception + */ + public function execute() + { + /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ + $collection = $this->filter->getCollection($this->collectionFactory->create()); + $collectionSize = $collection->getSize(); + + // Get id of the first item from addresses collection for providing it to the ResultRedirect and build a + // proper redirect URL + $customerId = $collection->getFirstItem()->getParentId(); + + /** @var \Magento\Customer\Model\Address $address */ + foreach ($collection as $address) { + $this->addressRepository->deleteById($address->getId()); + } + $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been deleted.', $collectionSize)); + + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + + return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php new file mode 100644 index 0000000000000..df041ac4e1202 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -0,0 +1,149 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Redirect; +use Psr\Log\LoggerInterface; + +/** + * Class for saving of customer address + */ +class Save extends Action +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory + */ + private $formFactory; + + /** + * @var \Magento\Customer\Api\CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var \Magento\Framework\Api\DataObjectHelper + */ + private $dataObjectHelper; + + /** + * @var \Magento\Customer\Api\Data\AddressInterfaceFactory + */ + private $addressDataFactory; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param Action\Context $context + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory + * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository + * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper + * @param \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory + * @param LoggerInterface $logger + */ + public function __construct( + Action\Context $context, + \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, + \Magento\Customer\Model\Metadata\FormFactory $formFactory, + \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, + \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, + \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory, + LoggerInterface $logger + ) { + parent::__construct($context); + $this->addressRepository = $addressRepository; + $this->formFactory = $formFactory; + $this->customerRepository = $customerRepository; + $this->dataObjectHelper = $dataObjectHelper; + $this->addressDataFactory = $addressDataFactory; + $this->logger = $logger; + } + + /** + * Execute action to save customer address + * + * @return \Magento\Framework\Controller\Result\Redirect + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function execute(): Redirect + { + $customerId = $this->getRequest()->getParam('parent_id', false); + $addressId = $this->getRequest()->getParam('entity_id', false); + /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ + $customer = $this->customerRepository->getById($customerId); + + try { + $addressForm = $this->formFactory->create( + 'customer_address', + 'adminhtml_customer_address', + [], + false, + false + ); + $addressData = $addressForm->extractData($this->getRequest()); + $addressData = $addressForm->compactData($addressData); + + $addressData['region'] = [ + 'region' => $addressData['region'] ?? null, + 'region_id' => $addressData['region_id'] ?? null, + ]; + $addressToSave = $this->addressDataFactory->create(); + $this->dataObjectHelper->populateWithArray( + $addressToSave, + $addressData, + \Magento\Customer\Api\Data\AddressInterface::class + ); + $addressToSave->setCustomerId($customer->getId()); + $addressToSave->setIsDefaultBilling( + (bool)$this->getRequest()->getParam('default_billing', false) + ); + $addressToSave->setIsDefaultShipping( + (bool)$this->getRequest()->getParam('default_shipping', false) + ); + if ($addressId) { + $addressToSave->setId($addressId); + $saveMessage = __('Customer address has been updated.'); + } else { + $addressToSave->setId(null); + $saveMessage = __('New customer address has been added.'); + } + + $this->addressRepository->save($addressToSave); + $this->messageManager->addSuccessMessage($saveMessage); + } catch (\Magento\Framework\Exception\LocalizedException $e) { + $this->messageManager->addErrorMessage($e->getMessage()); + $this->logger->critical($e); + } catch (\Exception $e) { + $this->messageManager->addExceptionMessage( + $e, __('We can\'t change customer address right now.') + ); + } + + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setPath( + 'customer/index/edit', + ['id' => $customerId, '_current' => true] + ); + return $resultRedirect; + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php new file mode 100644 index 0000000000000..01ce720a20e63 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; + +/** + * Class for validation of customer address form on admin. + */ +class Validate extends \Magento\Backend\App\Action implements HttpPostActionInterface, HttpGetActionInterface +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Framework\Controller\Result\JsonFactory + */ + private $resultJsonFactory; + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory + */ + private $formFactory; + + /** + * @param Action\Context $context + * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory + */ + public function __construct( + Action\Context $context, + \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, + \Magento\Customer\Model\Metadata\FormFactory $formFactory + ) { + parent::__construct($context); + $this->resultJsonFactory = $resultJsonFactory; + $this->formFactory = $formFactory; + } + + /** + * AJAX customer validation action + * + * @return \Magento\Framework\Controller\Result\Json + */ + public function execute() + { + /** @var \Magento\Framework\DataObject $response */ + $response = new \Magento\Framework\DataObject(); + $response->setError(0); + + /** @var \Magento\Framework\DataObject $validatedResponse */ + $validatedResponse = $this->validateCustomerAddress($response); + $resultJson = $this->resultJsonFactory->create(); + if ($validatedResponse->getError()) { + $validatedResponse->setError(true); + $validatedResponse->setMessages($response->getMessages()); + } + + $resultJson->setData($validatedResponse); + + return $resultJson; + } + + /** + * Customer address validation. + * + * @param \Magento\Framework\DataObject $response + * @return \Magento\Framework\DataObject + */ + private function validateCustomerAddress(\Magento\Framework\DataObject $response) + { + $addressForm = $this->formFactory->create('customer_address', 'adminhtml_customer_address'); + $formData = $addressForm->extractData($this->getRequest()); + + $errors = $addressForm->validateData($formData); + if ($errors !== true) { + $messages = $response->hasMessages() ? $response->getMessages() : []; + foreach ($errors as $error) { + $messages[] = $error; + } + $response->setMessages($messages); + $response->setError(1); + } + + return $response; + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php index 506eac3230200..be1b1aec7b3a3 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php @@ -14,6 +14,9 @@ use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; +/** + * Uploads files for customer address + */ class Upload extends Action { /** @@ -38,21 +41,29 @@ class Upload extends Action */ private $logger; + /** + * @var string + */ + private $scope; + /** * @param Context $context * @param FileUploaderFactory $fileUploaderFactory * @param AddressMetadataInterface $addressMetadataService * @param LoggerInterface $logger + * @param string $scope */ public function __construct( Context $context, FileUploaderFactory $fileUploaderFactory, AddressMetadataInterface $addressMetadataService, - LoggerInterface $logger + LoggerInterface $logger, + string $scope = 'address' ) { $this->fileUploaderFactory = $fileUploaderFactory; $this->addressMetadataService = $addressMetadataService; $this->logger = $logger; + $this->scope = $scope; parent::__construct($context); } @@ -69,14 +80,14 @@ public function execute() // Must be executed before any operations with $_FILES! $this->convertFilesArray(); - $attributeCode = key($_FILES['address']['name']); + $attributeCode = key($_FILES[$this->scope]['name']); $attributeMetadata = $this->addressMetadataService->getAttributeMetadata($attributeCode); /** @var FileUploader $fileUploader */ $fileUploader = $this->fileUploaderFactory->create([ 'attributeMetadata' => $attributeMetadata, 'entityTypeCode' => AddressMetadataInterface::ENTITY_TYPE_ADDRESS, - 'scope' => 'address', + 'scope' => $this->scope, ]); $errors = $fileUploader->validate(); @@ -114,14 +125,11 @@ public function execute() */ private function convertFilesArray() { - foreach ($_FILES['address'] as $itemKey => $item) { - foreach ($item as $value) { - if (is_array($value)) { - $_FILES['address'][$itemKey] = [ - key($value) => current($value), - ]; - } + foreach ($_FILES as $itemKey => $item) { + foreach ($item as $fieldName => $value) { + $_FILES[$this->scope][$fieldName] = [$itemKey => $value]; } + unset($_FILES[$itemKey]); } } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php index 45a7c0182d41c..aed7908337ee1 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php @@ -108,6 +108,7 @@ protected function _extractData( /** * Saves default_billing and default_shipping flags for customer address * + * @deprecated must be removed because addresses are save separately for now * @param array $addressIdList * @param array $extractedCustomerData * @return array @@ -150,6 +151,7 @@ protected function saveDefaultFlags(array $addressIdList, array & $extractedCust /** * Reformat customer addresses data to be compatible with customer service interface * + * @deprecated must be removed because addresses are save separately for now * @param array $extractedCustomerData * @return array */ @@ -188,7 +190,6 @@ public function execute() try { // optional fields might be set in request for future processing by observers in other modules $customerData = $this->_extractCustomerData(); - $addressesData = $this->_extractCustomerAddressData($customerData); if ($customerId) { $currentCustomer = $this->_customerRepository->getById($customerId); @@ -206,28 +207,12 @@ public function execute() $customerData, \Magento\Customer\Api\Data\CustomerInterface::class ); - $addresses = []; - foreach ($addressesData as $addressData) { - $region = isset($addressData['region']) ? $addressData['region'] : null; - $regionId = isset($addressData['region_id']) ? $addressData['region_id'] : null; - $addressData['region'] = [ - 'region' => $region, - 'region_id' => $regionId, - ]; - $addressDataObject = $this->addressDataFactory->create(); - $this->dataObjectHelper->populateWithArray( - $addressDataObject, - $addressData, - \Magento\Customer\Api\Data\AddressInterface::class - ); - $addresses[] = $addressDataObject; - } $this->_eventManager->dispatch( 'adminhtml_customer_prepare_save', ['customer' => $customer, 'request' => $this->getRequest()] ); - $customer->setAddresses($addresses); + if (isset($customerData['sendemail_store_id'])) { $customer->setStoreId($customerData['sendemail_store_id']); } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php index be09eb7daff76..67adf98d6c718 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php @@ -72,40 +72,6 @@ protected function _validateCustomer($response) return $customer; } - /** - * Customer address validation. - * - * @param \Magento\Framework\DataObject $response - * @return void - */ - protected function _validateCustomerAddress($response) - { - $addresses = $this->getRequest()->getPost('address'); - if (!is_array($addresses)) { - return; - } - foreach (array_keys($addresses) as $index) { - if ($index == '_template_') { - continue; - } - - $addressForm = $this->_formFactory->create('customer_address', 'adminhtml_customer_address'); - - $requestScope = sprintf('address/%s', $index); - $formData = $addressForm->extractData($this->getRequest(), $requestScope); - - $errors = $addressForm->validateData($formData); - if ($errors !== true) { - $messages = $response->hasMessages() ? $response->getMessages() : []; - foreach ($errors as $error) { - $messages[] = $error; - } - $response->setMessages($messages); - $response->setError(1); - } - } - } - /** * AJAX customer validation action * @@ -116,10 +82,7 @@ public function execute() $response = new \Magento\Framework\DataObject(); $response->setError(0); - $customer = $this->_validateCustomer($response); - if ($customer) { - $this->_validateCustomerAddress($response); - } + $this->_validateCustomer($response); $resultJson = $this->resultJsonFactory->create(); if ($response->getError()) { $response->setError(true); diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php new file mode 100644 index 0000000000000..34f4b8b4eca89 --- /dev/null +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -0,0 +1,574 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Model\Address; + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Type; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Ui\Component\Form\Field; +use Magento\Eav\Api\Data\AttributeInterface; +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Customer\Model\Attribute; +use Magento\Framework\App\ObjectManager; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Customer\Model\Address; +use Magento\Customer\Model\FileProcessor; +use Magento\Customer\Model\FileProcessorFactory; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * Dataprovider for customer address grid. + */ +class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider +{ + /** + * Maximum file size allowed for file_uploader UI component + */ + const MAX_FILE_SIZE = 2097152; + + /** + * @var \Magento\Customer\Model\ResourceModel\Address\Collection + */ + protected $collection; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var array + */ + private $loadedData; + + /** + * @var Config + */ + private $eavConfig; + + /** + * EAV attribute properties to fetch from meta storage + * @var array + */ + private $metaProperties = [ + 'dataType' => 'frontend_input', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ]; + + /** + * Form element mapping + * + * @var array + */ + private $formElement = [ + 'text' => 'input', + 'hidden' => 'input', + 'boolean' => 'checkbox', + ]; + + /** + * @var EavValidationRules + */ + private $eavValidationRules; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsiteSource; + + /** + * Allow to manage attributes, even they are hidden on storefront + * + * @var bool + */ + private $allowToShowHiddenAttributes; + + /* + * @var ContextInterface + */ + private $context; + + /** + * File types allowed for file_uploader UI component + * + * @var array + */ + private $fileUploaderTypes = [ + 'image', + 'file', + ]; + + /** + * @var \Magento\Customer\Model\Config\Share + */ + private $shareConfig; + + /** + * @var FileProcessorFactory + */ + private $fileProcessorFactory; + + /** + * @var array + */ + private $bannedInputTypes = ['media_image']; + + /** + * @var array + */ + private $attributesToEliminate = [ + 'region', + 'vat_is_valid', + 'vat_request_date', + 'vat_request_id', + 'vat_request_success' + ]; + + /** + * DataProvider constructor. + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName + * @param CollectionFactory $addressCollectionFactory + * @param CustomerRepositoryInterface $customerRepository + * @param Config $eavConfig + * @param EavValidationRules $eavValidationRules + * @param ContextInterface $context + * @param FileProcessorFactory $fileProcessorFactory + * @param \Magento\Customer\Model\Config\Share $shareConfig + * @param array $meta + * @param array $data + * @param bool $allowToShowHiddenAttributes + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function __construct( + $name, + $primaryFieldName, + $requestFieldName, + CollectionFactory $addressCollectionFactory, + CustomerRepositoryInterface $customerRepository, + Config $eavConfig, + EavValidationRules $eavValidationRules, + ContextInterface $context, + FileProcessorFactory $fileProcessorFactory, + \Magento\Customer\Model\Config\Share $shareConfig, + array $meta = [], + array $data = [], + $allowToShowHiddenAttributes = true + ) { + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->collection = $addressCollectionFactory->create(); + $this->collection->addAttributeToSelect('*'); + $this->customerRepository = $customerRepository; + $this->eavValidationRules = $eavValidationRules; + $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; + $this->context = $context; + $this->fileProcessorFactory = $fileProcessorFactory; + $this->shareConfig = $shareConfig; + $this->meta['general']['children'] = $this->getAttributesMeta( + $eavConfig->getEntityType('customer_address') + ); + } + + /** + * Get Addresses data and process customer default billing & shipping addresses + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getData() + { + if (null !== $this->loadedData) { + return $this->loadedData; + } + $items = $this->collection->getItems(); + /** @var Address $item */ + foreach ($items as $item) { + $addressId = $item->getEntityId(); + $item->load($addressId); + $this->loadedData[$addressId] = $item->getData(); + $customerId = $this->loadedData[$addressId]['parent_id']; + /** @var \Magento\Customer\Model\Customer $customer */ + $customer = $this->customerRepository->getById($customerId); + $defaultBilling = $customer->getDefaultBilling(); + $defaultShipping = $customer->getDefaultShipping(); + $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); + $this->overrideFileUploaderData($item, $this->loadedData[$addressId]); + } + + if (null === $this->loadedData) { + $this->loadedData[''] = $this->getDefaultData(); + } + + return $this->loadedData; + } + + /** + * Prepare address data + * + * @param int $addressId + * @param array $addresses + * @param string|null $defaultBilling + * @param string|null $defaultShipping + * @return void + */ + private function prepareAddressData($addressId, array &$addresses, $defaultBilling, $defaultShipping) + { + if (null !== $defaultBilling && $addressId == $defaultBilling) { + $addresses[$addressId]['default_billing'] = '1'; + } + if (null !== $defaultShipping && $addressId == $defaultShipping) { + $addresses[$addressId]['default_shipping'] = '1'; + } + if (null !== $addresses[$addressId]['street'] && !is_array($addresses[$addressId]['street'])) { + $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); + } + } + + /** + * Get default customer data for adding new address + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @return array + */ + private function getDefaultData() + { + $parentId = $this->context->getRequestParam('parent_id'); + $customer = $this->customerRepository->getById($parentId); + $data = [ + 'parent_id' => $parentId, + 'firstname' => $customer->getFirstname(), + 'lastname' => $customer->getLastname() + ]; + + return $data; + } + + /** + * Override file uploader UI component data + * + * Overrides data for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Address $entity + * @param array $entityData + * @return void + */ + private function overrideFileUploaderData($entity, array &$entityData) + { + $attributes = $entity->getAttributes(); + foreach ($attributes as $attribute) { + /** @var Attribute $attribute */ + if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( + $entity->getEntityType(), + $attribute, + $entityData + ); + } + } + } + + /** + * Get attributes meta + * + * @param Type $entityType + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getAttributesMeta(Type $entityType): array + { + $meta = []; + $attributes = $entityType->getAttributeCollection(); + /* @var AbstractAttribute $attribute */ + foreach ($attributes as $attribute) { + $this->processFrontendInput($attribute, $meta); + + $code = $attribute->getAttributeCode(); + + if (in_array($attribute->getFrontendInput(), $this->bannedInputTypes)) { + continue; + } + if (in_array($attribute->getAttributeCode(), $this->attributesToEliminate)) { + continue; + } + + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value + foreach ($this->metaProperties as $metaName => $origName) { + $value = $attribute->getDataUsingMethod($origName); + $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; + if ('frontend_input' === $origName) { + $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; + } + } + + if ($attribute->usesSource()) { + if ($code == AddressInterface::COUNTRY_ID) { + $meta[$code]['arguments']['data']['config']['options'] = $this->getCountryWithWebsiteSource() + ->getAllOptions(); + } else { + $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } + } + + $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); + if (!empty($rules)) { + $meta[$code]['arguments']['data']['config']['validation'] = $rules; + } + + $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; + $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); + + $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + } + + $this->processWebsiteMeta($meta); + return $meta; + } + + /** + * Process attributes by frontend input type + * + * @param AttributeInterface $attribute + * @param array $meta + * @return void + */ + private function processFrontendInput(AttributeInterface $attribute, array &$meta) + { + $code = $attribute->getAttributeCode(); + if ($attribute->getFrontendInput() === 'boolean') { + $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; + $meta[$code]['arguments']['data']['config']['valueMap'] = [ + 'true' => '1', + 'false' => '0', + ]; + } + } + + /** + * Retrieve Country With Websites Source + * + * @return CountryWithWebsites + * @deprecated 100.2.0 + */ + private function getCountryWithWebsiteSource(): CountryWithWebsites + { + if (!$this->countryWithWebsiteSource) { + $this->countryWithWebsiteSource = ObjectManager::getInstance()->get(CountryWithWebsites::class); + } + + return $this->countryWithWebsiteSource; + } + + /** + * Detect can we show attribute on specific form or not + * + * @param Attribute $customerAttribute + * @return bool + */ + private function canShowAttribute(AbstractAttribute $customerAttribute): bool + { + $userDefined = (bool) $customerAttribute->getIsUserDefined(); + if (!$userDefined) { + return $customerAttribute->getIsVisible(); + } + + $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); + + return ($this->allowToShowHiddenAttributes && $canShowOnForm) || + (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); + } + + /** + * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... + * + * @param Attribute $customerAttribute + * @return bool + */ + private function canShowAttributeInForm(AbstractAttribute $customerAttribute): bool + { + $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; + + if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { + return is_array($customerAttribute->getUsedInForms()) && + ( + (in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || + (in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) + ); + } + return is_array($customerAttribute->getUsedInForms()) && + in_array('customer_address_edit', $customerAttribute->getUsedInForms()); + } + + /** + * Override file uploader UI component metadata + * + * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Type $entityType + * @param AbstractAttribute $attribute + * @param array $config + * @return void + */ + private function overrideFileUploaderMetadata( + Type $entityType, + AbstractAttribute $attribute, + array &$config + ) { + if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $maxFileSize = self::MAX_FILE_SIZE; + + if (isset($config['validation']['max_file_size'])) { + $maxFileSize = (int)$config['validation']['max_file_size']; + } + + $allowedExtensions = []; + + if (isset($config['validation']['file_extensions'])) { + $allowedExtensions = explode(',', $config['validation']['file_extensions']); + array_walk($allowedExtensions, function (&$value) { + $value = strtolower(trim($value)); + }); + } + + $allowedExtensions = implode(' ', $allowedExtensions); + + $entityTypeCode = $entityType->getEntityTypeCode(); + $url = $this->getFileUploadUrl($entityTypeCode); + + $config = [ + 'formElement' => 'fileUploader', + 'componentType' => 'fileUploader', + 'maxFileSize' => $maxFileSize, + 'allowedExtensions' => $allowedExtensions, + 'uploaderConfig' => [ + 'url' => $url, + ], + 'label' => $this->getMetadataValue($config, 'label'), + 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), + 'required' => $this->getMetadataValue($config, 'required'), + 'visible' => $this->getMetadataValue($config, 'visible'), + 'validation' => $this->getMetadataValue($config, 'validation'), + ]; + } + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + private function processWebsiteMeta(&$meta) + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => 'customer_form.customer_form_data_source:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } + + /** + * Retrieve metadata value + * + * @param array $config + * @param string $name + * @param mixed $default + * @return mixed + */ + private function getMetadataValue($config, $name, $default = null) + { + return $config[$name] ?? $default; + } + + /** + * Retrieve URL to file upload + * + * @param string $entityTypeCode + * @return string + */ + private function getFileUploadUrl($entityTypeCode): string + { + switch ($entityTypeCode) { + case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: + $url = 'customer/file/customer_upload'; + break; + + case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: + $url = 'customer/file/address_upload'; + break; + + default: + $url = ''; + break; + } + return $url; + } + + /** + * Retrieve array of values required by file uploader UI component + * + * @param Type $entityType + * @param Attribute $attribute + * @param array $customerData + * @return array + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + private function getFileUploaderData( + Type $entityType, + Attribute $attribute, + array $customerData + ): array { + $attributeCode = $attribute->getAttributeCode(); + + $file = $customerData[$attributeCode] ?? ''; + + /** @var FileProcessor $fileProcessor */ + $fileProcessor = $this->fileProcessorFactory->create([ + 'entityTypeCode' => $entityType->getEntityTypeCode(), + ]); + + if (!empty($file) + && $fileProcessor->isExist($file) + ) { + $stat = $fileProcessor->getStat($file); + $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); + + return [ + [ + 'file' => $file, + 'size' => null !== $stat ? $stat['size'] : 0, + 'url' => $viewUrl ?? '', + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), + ], + ]; + } + + return []; + } +} diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php new file mode 100644 index 0000000000000..d52c94fb034c6 --- /dev/null +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -0,0 +1,585 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model\Customer; + +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Address; +use Magento\Customer\Model\Attribute; +use Magento\Customer\Model\Customer; +use Magento\Customer\Model\FileProcessor; +use Magento\Customer\Model\FileProcessorFactory; +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory; +use Magento\Eav\Api\Data\AttributeInterface; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Eav\Model\Entity\Type; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Session\SessionManagerInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Ui\Component\Form\Field; +use Magento\Ui\DataProvider\EavValidationRules; + +/** + * Refactored version of Magento\Customer\Model\Customer\DataProvider with eliminated usage of addresses collection. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\AbstractDataProvider +{ + /** + * Maximum file size allowed for file_uploader UI component + */ + const MAX_FILE_SIZE = 2097152; + + /** + * @var array + */ + private $loadedData; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsiteSource; + + /** + * @var \Magento\Customer\Model\Config\Share + */ + private $shareConfig; + + /** + * EAV attribute properties to fetch from meta storage + * @var array + */ + private $metaProperties = [ + 'dataType' => 'frontend_input', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ]; + + /** + * Form element mapping + * + * @var array + */ + private $formElement = [ + 'text' => 'input', + 'hidden' => 'input', + 'boolean' => 'checkbox', + ]; + + /** + * @var EavValidationRules + */ + private $eavValidationRules; + + /** + * @var SessionManagerInterface + * @since 100.1.0 + */ + private $session; + + /** + * @var FileProcessorFactory + */ + private $fileProcessorFactory; + + /** + * File types allowed for file_uploader UI component + * + * @var array + */ + private $fileUploaderTypes = [ + 'image', + 'file', + ]; + + /** + * Customer fields that must be removed + * + * @var array + */ + private $forbiddenCustomerFields = [ + 'password_hash', + 'rp_token', + 'confirmation', + ]; + + /* + * @var ContextInterface + */ + private $context; + + /** + * Allow to manage attributes, even they are hidden on storefront + * + * @var bool + */ + private $allowToShowHiddenAttributes; + + /** + * @var \Magento\Directory\Model\CountryFactory + */ + private $countryFactory; + + /** + * DataProviderWithDefaultAddresses constructor. + * + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName + * @param EavValidationRules $eavValidationRules + * @param CustomerCollectionFactory $customerCollectionFactory + * @param Config $eavConfig + * @param FileProcessorFactory $fileProcessorFactory + * @param ContextInterface $context + * @param \Magento\Directory\Model\CountryFactory $countryFactory + * @param SessionManagerInterface $session + * @param \Magento\Customer\Model\Config\Share $shareConfig + * @param CountryWithWebsites $countryWithWebsites + * @param bool $allowToShowHiddenAttributes + * @param array $meta + * @param array $data + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function __construct( + string $name, + string $primaryFieldName, + string $requestFieldName, + EavValidationRules $eavValidationRules, + CustomerCollectionFactory $customerCollectionFactory, + Config $eavConfig, + FileProcessorFactory $fileProcessorFactory, + ContextInterface $context, + \Magento\Directory\Model\CountryFactory $countryFactory, + \Magento\Framework\Session\SessionManagerInterface $session, + \Magento\Customer\Model\Config\Share $shareConfig, + CountryWithWebsites $countryWithWebsites, + $allowToShowHiddenAttributes = true, + array $meta = [], + array $data = [] + ) { + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->eavValidationRules = $eavValidationRules; + $this->collection = $customerCollectionFactory->create(); + $this->collection->addAttributeToSelect('*'); + $this->fileProcessorFactory = $fileProcessorFactory; + $this->context = $context ?: ObjectManager::getInstance()->get(ContextInterface::class); + $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; + $this->session = $session; + $this->countryWithWebsiteSource = $countryWithWebsites; + $this->shareConfig = $shareConfig; + $this->countryFactory = $countryFactory; + $this->meta['customer']['children'] = $this->getAttributesMeta( + $eavConfig->getEntityType('customer') + ); +// $this->meta['address']['children'] = $this->getAttributesMeta( +// $eavConfig->getEntityType('customer_address') +// ); + } + + /** + * Get data + * + * @return array + */ + public function getData() + { + if (null !== $this->loadedData) { + return $this->loadedData; + } + $items = $this->collection->getItems(); + /** @var Customer $customer */ + foreach ($items as $customer) { + $result['customer'] = $customer->getData(); + + $this->overrideFileUploaderData($customer, $result['customer']); + + $result['customer'] = array_diff_key( + $result['customer'], + array_flip($this->forbiddenCustomerFields) + ); + unset($result['address']); + + $result['default_billing_address'] = $this->prepareDefaultAddress( + $customer->getDefaultBillingAddress() + ); + $result['default_shipping_address'] = $this->prepareDefaultAddress( + $customer->getDefaultShippingAddress() + ); + $result['customer_id'] = $customer->getId(); + + $this->loadedData[$customer->getId()] = $result; + } + + $data = $this->session->getCustomerFormData(); + if (!empty($data)) { + $customerId = $data['customer']['entity_id'] ?? null; + $this->loadedData[$customerId] = $data; + $this->session->unsCustomerFormData(); + } + + return $this->loadedData; + } + + /** + * Prepare default address data. + * + * @param Address|false $address + * @return array + */ + private function prepareDefaultAddress($address): array + { + $addressData = []; + + if (!empty($address)) { + $addressData = $address->getData(); + if (isset($addressData['street']) && !\is_array($address['street'])) { + $addressData['street'] = explode("\n", $addressData['street']); + } + $addressData['country'] = $this->countryFactory->create() + ->loadByCode($addressData['country_id'])->getName(); + } + + return $addressData; + } + + /** + * Override file uploader UI component data + * + * Overrides data for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Customer|Address $entity + * @param array $entityData + * @return void + */ + private function overrideFileUploaderData($entity, array &$entityData) + { + $attributes = $entity->getAttributes(); + foreach ($attributes as $attribute) { + /** @var Attribute $attribute */ + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( + $entity->getEntityType(), + $attribute, + $entityData + ); + } + } + } + + /** + * Retrieve array of values required by file uploader UI component + * + * @param Type $entityType + * @param Attribute $attribute + * @param array $customerData + * @return array + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + private function getFileUploaderData( + Type $entityType, + Attribute $attribute, + array $customerData + ): array { + $attributeCode = $attribute->getAttributeCode(); + + $file = $customerData[$attributeCode] ?? ''; + + /** @var FileProcessor $fileProcessor */ + $fileProcessor = $this->getFileProcessorFactory()->create([ + 'entityTypeCode' => $entityType->getEntityTypeCode(), + ]); + + if (!empty($file) + && $fileProcessor->isExist($file) + ) { + $stat = $fileProcessor->getStat($file); + $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); + + return [ + [ + 'file' => $file, + 'size' => null !== $stat ? $stat['size'] : 0, + 'url' => $viewUrl ?? '', + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), + ], + ]; + } + + return []; + } + + /** + * Get attributes meta + * + * @param Type $entityType + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getAttributesMeta(Type $entityType): array + { + $meta = []; + $attributes = $entityType->getAttributeCollection(); + /* @var AbstractAttribute $attribute */ + foreach ($attributes as $attribute) { + $this->processFrontendInput($attribute, $meta); + + $code = $attribute->getAttributeCode(); + + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value + foreach ($this->metaProperties as $metaName => $origName) { + $value = $attribute->getDataUsingMethod($origName); + $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; + if ('frontend_input' === $origName) { + $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; + } + } + + if ($attribute->usesSource()) { + if ($code == AddressInterface::COUNTRY_ID) { + $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource + ->getAllOptions(); + } else { + $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } + } + + $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); + if (!empty($rules)) { + $meta[$code]['arguments']['data']['config']['validation'] = $rules; + } + + $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; + $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); + + $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + } + + $this->processWebsiteMeta($meta); + return $meta; + } + + /** + * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... + * + * @param AbstractAttribute $customerAttribute + * @return bool + */ + private function canShowAttributeInForm(AbstractAttribute $customerAttribute) + { + $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; + + if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { + return \is_array($customerAttribute->getUsedInForms()) && + ( + (\in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || + (\in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) + ); + } + return \is_array($customerAttribute->getUsedInForms()) && + \in_array('customer_address_edit', $customerAttribute->getUsedInForms()); + } + + /** + * Detect can we show attribute on specific form or not + * + * @param AbstractAttribute $customerAttribute + * @return bool + */ + private function canShowAttribute(AbstractAttribute $customerAttribute) + { + $userDefined = (bool) $customerAttribute->getIsUserDefined(); + if (!$userDefined) { + return $customerAttribute->getIsVisible(); + } + + $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); + + return ($this->allowToShowHiddenAttributes && $canShowOnForm) || + (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + private function processWebsiteMeta(&$meta) + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } + + /** + * Override file uploader UI component metadata + * + * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Type $entityType + * @param AbstractAttribute $attribute + * @param array $config + * @return void + */ + private function overrideFileUploaderMetadata( + Type $entityType, + AbstractAttribute $attribute, + array &$config + ) { + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $maxFileSize = self::MAX_FILE_SIZE; + + if (isset($config['validation']['max_file_size'])) { + $maxFileSize = (int)$config['validation']['max_file_size']; + } + + $allowedExtensions = []; + + if (isset($config['validation']['file_extensions'])) { + $allowedExtensions = explode(',', $config['validation']['file_extensions']); + array_walk($allowedExtensions, function (&$value) { + $value = strtolower(trim($value)); + }); + } + + $allowedExtensions = implode(' ', $allowedExtensions); + + $entityTypeCode = $entityType->getEntityTypeCode(); + $url = $this->getFileUploadUrl($entityTypeCode); + + $config = [ + 'formElement' => 'fileUploader', + 'componentType' => 'fileUploader', + 'maxFileSize' => $maxFileSize, + 'allowedExtensions' => $allowedExtensions, + 'uploaderConfig' => [ + 'url' => $url, + ], + 'label' => $this->getMetadataValue($config, 'label'), + 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), + 'required' => $this->getMetadataValue($config, 'required'), + 'visible' => $this->getMetadataValue($config, 'visible'), + 'validation' => $this->getMetadataValue($config, 'validation'), + ]; + } + } + + /** + * Retrieve metadata value + * + * @param array $config + * @param string $name + * @param mixed $default + * @return mixed + */ + private function getMetadataValue($config, $name, $default = null) + { + return $config[$name] ?? $default; + } + + /** + * Retrieve URL to file upload + * + * @param string $entityTypeCode + * @return string + */ + private function getFileUploadUrl($entityTypeCode): string + { + switch ($entityTypeCode) { + case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: + $url = 'customer/file/customer_upload'; + break; + + case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: + $url = 'customer/file/address_upload'; + break; + + default: + $url = ''; + break; + } + return $url; + } + + /** + * Process attributes by frontend input type + * + * @param AttributeInterface $attribute + * @param array $meta + * @return void + */ + private function processFrontendInput(AttributeInterface $attribute, array &$meta) + { + $code = $attribute->getAttributeCode(); + if ($attribute->getFrontendInput() === 'boolean') { + $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; + $meta[$code]['arguments']['data']['config']['valueMap'] = [ + 'true' => '1', + 'false' => '0', + ]; + } + } + + /** + * Prepare address data + * + * @param int $addressId + * @param array $addresses + * @param array $customer + * @return void + */ + protected function prepareAddressData($addressId, array &$addresses, array $customer) + { + if (isset($customer['default_billing']) + && $addressId == $customer['default_billing'] + ) { + $addresses[$addressId]['default_billing'] = $customer['default_billing']; + } + if (isset($customer['default_shipping']) + && $addressId == $customer['default_shipping'] + ) { + $addresses[$addressId]['default_shipping'] = $customer['default_shipping']; + } + if (isset($addresses[$addressId]['street']) && !\is_array($addresses[$addressId]['street'])) { + $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); + } + } + + /** + * Get FileProcessorFactory instance + * + * @return FileProcessorFactory + * @deprecated 100.1.3 + */ + private function getFileProcessorFactory(): FileProcessorFactory + { + if ($this->fileProcessorFactory === null) { + $this->fileProcessorFactory = ObjectManager::getInstance() + ->get(\Magento\Customer\Model\FileProcessorFactory::class); + } + return $this->fileProcessorFactory; + } +} diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index e6e9c2b50c068..aca5b277186ca 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -109,7 +109,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) $extend = $this->_getRequestValue($request); $attrCode = $this->getAttribute()->getAttributeCode(); - if ($this->_requestScope) { + if ($this->_requestScope || !isset($_FILES[$attrCode])) { $value = []; if (strpos($this->_requestScope, '/') !== false) { $scopes = explode('/', $this->_requestScope); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php new file mode 100644 index 0000000000000..83129fee9b59b --- /dev/null +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -0,0 +1,171 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model\ResourceModel\Address\Grid; + +use Magento\Framework\Api\Search\SearchResultInterface; +use Magento\Framework\Api\Search\AggregationInterface; +use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; +use Magento\Framework\View\Element\UiComponent\Context; + +/** + * Class getting collection of addresses assigned to customer + */ +class Collection extends AbstractCollection implements SearchResultInterface +{ + /** + * @var string + */ + protected $_idFieldName = 'entity_id'; + + /** + * @var Context + */ + private $context; + + /** + * @var AggregationInterface + */ + protected $aggregations; + + /** + * @param Context $context + * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory + * @param \Psr\Log\LoggerInterface $logger + * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy + * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param string $mainTable + * @param string $eventPrefix + * @param string $eventObject + * @param string $resourceModel + * @param string $model + * @param \Magento\Framework\DB\Adapter\AdapterInterface|string|null $connection + * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct( + Context $context, + \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory, + \Psr\Log\LoggerInterface $logger, + \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, + \Magento\Framework\Event\ManagerInterface $eventManager, + $mainTable, + $eventPrefix, + $eventObject, + $resourceModel, + $model = \Magento\Framework\View\Element\UiComponent\DataProvider\Document::class, + $connection = null, + \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null + ) { + $this->context = $context; + $this->_eventPrefix = $eventPrefix; + $this->_eventObject = $eventObject; + $this->_init($model, $resourceModel); + $this->setMainTable($mainTable); + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $connection, + $resource + ); + } + + /** + * Resource initialization + * + * @return $this + */ + protected function _initSelect() + { + parent::_initSelect(); + $parentId = $this->context->getRequestParam('parent_id'); + if ($parentId !== null) { + $this->getSelect()->where('parent_id=?', $parentId); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @return AggregationInterface + */ + public function getAggregations() + { + return $this->aggregations; + } + + /** + * {@inheritdoc} + * + * @param AggregationInterface $aggregations + * @return $this + */ + public function setAggregations($aggregations) + { + $this->aggregations = $aggregations; + return $this; + } + + /** + * Get search criteria. + * + * @return \Magento\Framework\Api\SearchCriteriaInterface|null + */ + public function getSearchCriteria() + { + return null; + } + + /** + * Set search criteria. + * + * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setSearchCriteria(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria = null) + { + return $this; + } + + /** + * Get total count. + * + * @return int + */ + public function getTotalCount() + { + return $this->getSize(); + } + + /** + * Set total count. + * + * @param int $totalCount + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setTotalCount($totalCount) + { + return $this; + } + + /** + * Set items list. + * + * @param \Magento\Framework\Api\ExtensibleDataInterface[] $items + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setItems(array $items = null) + { + return $this; + } +} diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index d473a4dc01891..cbfebe87812bc 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -38,16 +38,26 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) /** * @var $object \Magento\Customer\Model\Address */ - if (!$object->getIsCustomerSaveTransaction() && $this->isAddressDefault($object)) { + if (!$object->getIsCustomerSaveTransaction() && $object->getId()) { $customer = $this->customerFactory->create()->load($object->getCustomerId()); $changedAddresses = []; if ($object->getIsDefaultBilling()) { $changedAddresses['default_billing'] = $object->getId(); + } elseif ($customer->getDefaultBillingAddress() + && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() + && !$object->getIsDefaultBilling() + ) { + $changedAddresses['default_billing'] = null; } if ($object->getIsDefaultShipping()) { $changedAddresses['default_shipping'] = $object->getId(); + } elseif ($customer->getDefaultShippingAddress() + && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() + && !$object->getIsDefaultShipping() + ) { + $changedAddresses['default_shipping'] = null; } if ($changedAddresses) { @@ -63,6 +73,9 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) /** * Checks if address has chosen as default and has had an id * + * @deprecated Is not used anymore due to changes in logic of save of address. + * If address was default and becomes not default than default address id for customer must be + * set to null * @param \Magento\Framework\Model\AbstractModel $object * @return bool */ diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 43ae2db0c2163..5d88cd92c1730 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -170,22 +170,18 @@ public function save(CustomerInterface $customer, $passwordHash = null) /** @var NewOperation|null $delegatedNewOperation */ $delegatedNewOperation = !$customer->getId() ? $this->delegatedStorage->consumeNewOperation() : null; $prevCustomerData = null; - $prevCustomerDataArr = null; if ($customer->getId()) { $prevCustomerData = $this->getById($customer->getId()); - $prevCustomerDataArr = $prevCustomerData->__toArray(); } - /** @var $customer \Magento\Customer\Model\Data\Customer */ - $customerArr = $customer->__toArray(); + $customer = $this->imageProcessor->save( $customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $prevCustomerData ); - $origAddresses = $customer->getAddresses(); - $customer->setAddresses([]); + + /** @var array $customerData */ $customerData = $this->extensibleDataObjectConverter->toNestedArray($customer, [], CustomerInterface::class); - $customer->setAddresses($origAddresses); /** @var Customer $customerModel */ $customerModel = $this->customerFactory->create(['data' => $customerData]); //Model's actual ID field maybe different than "id" so "id" field from $customerData may be ignored. @@ -200,51 +196,10 @@ public function save(CustomerInterface $customer, $passwordHash = null) $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } - if (!array_key_exists('default_billing', $customerArr) - && null !== $prevCustomerDataArr - && array_key_exists('default_billing', $prevCustomerDataArr) - ) { - $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); - } - if (!array_key_exists('default_shipping', $customerArr) - && null !== $prevCustomerDataArr - && array_key_exists('default_shipping', $prevCustomerDataArr) - ) { - $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); - } $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); - if (!$customer->getAddresses() - && $delegatedNewOperation - && $delegatedNewOperation->getCustomer()->getAddresses() - ) { - $customer->setAddresses($delegatedNewOperation->getCustomer()->getAddresses()); - } - if ($customer->getAddresses() !== null) { - if ($customer->getId()) { - $existingAddresses = $this->getById($customer->getId())->getAddresses(); - $getIdFunc = function ($address) { - return $address->getId(); - }; - $existingAddressIds = array_map($getIdFunc, $existingAddresses); - } else { - $existingAddressIds = []; - } - $savedAddressIds = []; - foreach ($customer->getAddresses() as $address) { - $address->setCustomerId($customerId) - ->setRegion($address->getRegion()); - $this->addressRepository->save($address); - if ($address->getId()) { - $savedAddressIds[] = $address->getId(); - } - } - $addressIdsToDelete = array_diff($existingAddressIds, $savedAddressIds); - foreach ($addressIdsToDelete as $addressId) { - $this->addressRepository->deleteById($addressId); - } - } + $this->customerRegistry->remove($customerId); $savedCustomer = $this->get($customer->getEmail(), $customer->getWebsiteId()); $this->eventManager->dispatch( @@ -374,7 +329,6 @@ public function deleteById($customerId) * @param \Magento\Framework\Api\Search\FilterGroup $filterGroup * @param \Magento\Customer\Model\ResourceModel\Customer\Collection $collection * @return void - * @throws \Magento\Framework\Exception\InputException */ protected function addFilterGroupToCollection( \Magento\Framework\Api\Search\FilterGroup $filterGroup, diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php new file mode 100644 index 0000000000000..47088eece23ed --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php @@ -0,0 +1,205 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Test\Unit\Controller\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class SaveTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Customer\Controller\Adminhtml\Address\Save + */ + private $model; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressRepositoryMock; + + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $formFactoryMock; + + /** + * @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $customerRepositoryMock; + + /** + * @var \Magento\Framework\Api\DataObjectHelper|\PHPUnit_Framework_MockObject_MockObject + */ + private $dataObjectHelperMock; + + /** + * @var \Magento\Customer\Api\Data\AddressInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressDataFactoryMock; + + /** + * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $loggerMock; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultRedirectFactoryMock; + + /** + * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageManagerMock; + + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->addressRepositoryMock = $this->createMock(\Magento\Customer\Api\AddressRepositoryInterface::class); + $this->formFactoryMock = $this->createMock(\Magento\Customer\Model\Metadata\FormFactory::class); + $this->customerRepositoryMock = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); + $this->dataObjectHelperMock = $this->createMock(\Magento\Framework\Api\DataObjectHelper ::class); + $this->addressDataFactoryMock = $this->createMock(\Magento\Customer\Api\Data\AddressInterfaceFactory::class); + $this->loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + $this->resultRedirectFactoryMock = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); + $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\ManagerInterface::class); + + $objectManager = new ObjectManagerHelper($this); + + $this->model = $objectManager->getObject( + \Magento\Customer\Controller\Adminhtml\Address\Save::class, + [ + 'addressRepository' => $this->addressRepositoryMock, + 'formFactory' => $this->formFactoryMock, + 'customerRepository' => $this->customerRepositoryMock, + 'dataObjectHelper' => $this->dataObjectHelperMock, + 'addressDataFactory' => $this->addressDataFactoryMock, + 'loggerMock' => $this->loggerMock, + 'request' => $this->requestMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock, + 'messageManager' => $this->messageManagerMock, + ] + ); + } + + /** + * Test method \Magento\Customer\Controller\Adminhtml\Address\Save::execute + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testExecute() + { + $addressId = 11; + $customerId = 22; + + $addressExtractedData = [ + 'entity_id' => $addressId, + 'code' => 'value', + 'coolness' => false, + 'region' => 'region', + 'region_id' => 'region_id', + ]; + + $addressCompactedData = [ + 'entity_id' => $addressId, + 'default_billing' => 'true', + 'default_shipping' => 'true', + 'code' => 'value', + 'coolness' => false, + 'region' => 'region', + 'region_id' => 'region_id', + ]; + + $mergedAddressData = [ + 'entity_id' => $addressId, + 'default_billing' => true, + 'default_shipping' => true, + 'code' => 'value', + 'region' => [ + 'region' => 'region', + 'region_id' => 'region_id', + ], + 'region_id' => 'region_id', + 'id' => $addressId, + ]; + + $this->requestMock->method('getParam') + ->withConsecutive(['parent_id'], ['entity_id']) + ->willReturnOnConsecutiveCalls(22, 1); + + $customerMock = $this->getMockBuilder( + \Magento\Customer\Api\Data\CustomerInterface::class + )->disableOriginalConstructor()->getMock(); + + $this->customerRepositoryMock->expects($this->atLeastOnce()) + ->method('getById') + ->with($customerId) + ->willReturn($customerMock); + + $customerAddressFormMock = $this->createMock(\Magento\Customer\Model\Metadata\Form::class); + + $customerAddressFormMock->expects($this->atLeastOnce()) + ->method('extractData') + ->with($this->requestMock) + ->willReturn($addressExtractedData); + $customerAddressFormMock->expects($this->once()) + ->method('compactData') + ->with($addressExtractedData) + ->willReturn($addressCompactedData); + + $this->formFactoryMock->expects($this->exactly(1)) + ->method('create') + ->willReturn($customerAddressFormMock); + + $addressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->addressDataFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($addressMock); + + $this->dataObjectHelperMock->expects($this->atLeastOnce()) + ->method('populateWithArray') + ->willReturn( + [ + $addressMock, + $mergedAddressData, \Magento\Customer\Api\Data\AddressInterface::class, + $this->dataObjectHelperMock, + ] + ); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccessMessage') + ->with(__('Customer address has been updated.')) + ->willReturnSelf(); + + $resultRedirect = $this->createMock(\Magento\Framework\Controller\Result\Redirect::class); + $resultRedirect->expects($this->atLeastOnce()) + ->method('setPath') + ->with('customer/index/edit', ['id' => $customerId, '_current' => true]) + ->willReturnSelf(); + $this->resultRedirectFactoryMock->method('create') + ->willReturn($resultRedirect); + + $this->assertEquals($resultRedirect, $this->model->execute()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php new file mode 100644 index 0000000000000..a724bdd24959b --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php @@ -0,0 +1,118 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Test\Unit\Controller\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ValidateTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Customer\Controller\Adminhtml\Address\Validate + */ + private $model; + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $formFactoryMock; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultRedirectFactoryMock; + + /** + * @var \Magento\Framework\Controller\Result\JsonFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultJsonFactoryMock; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->formFactoryMock = $this->createMock(\Magento\Customer\Model\Metadata\FormFactory::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + $this->resultJsonFactoryMock = $this->createMock(\Magento\Framework\Controller\Result\JsonFactory::class); + $this->resultRedirectFactoryMock = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); + + $objectManager = new ObjectManagerHelper($this); + + $this->model = $objectManager->getObject( + \Magento\Customer\Controller\Adminhtml\Address\Validate::class, + [ + 'formFactory' => $this->formFactoryMock, + 'request' => $this->requestMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock, + 'resultJsonFactory' => $this->resultJsonFactoryMock, + ] + ); + } + + /** + * Test method \Magento\Customer\Controller\Adminhtml\Address\Save::execute + * + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testExecute() + { + $addressId = 11; + $errors = ['Error Message 1', 'Error Message 2']; + + $addressExtractedData = [ + 'entity_id' => $addressId, + 'default_billing' => true, + 'default_shipping' => true, + 'code' => 'value', + 'region' => [ + 'region' => 'region', + 'region_id' => 'region_id', + ], + 'region_id' => 'region_id', + 'id' => $addressId, + ]; + + $customerAddressFormMock = $this->createMock(\Magento\Customer\Model\Metadata\Form::class); + + $customerAddressFormMock->expects($this->atLeastOnce()) + ->method('extractData') + ->with($this->requestMock) + ->willReturn($addressExtractedData); + $customerAddressFormMock->expects($this->once()) + ->method('validateData') + ->with($addressExtractedData) + ->willReturn($errors); + + $this->formFactoryMock->expects($this->exactly(1)) + ->method('create') + ->willReturn($customerAddressFormMock); + + $resultJson = $this->createMock(\Magento\Framework\Controller\Result\Json::class); + $this->resultJsonFactoryMock->method('create') + ->willReturn($resultJson); + + $validateResponseMock = $this->createPartialMock( + \Magento\Framework\DataObject::class, + ['getError', 'setMessages'] + ); + $validateResponseMock->method('setMessages')->willReturnSelf(); + $validateResponseMock->method('getError')->willReturn(1); + + $resultJson->method('setData')->willReturnSelf(); + + $this->assertEquals($resultJson, $this->model->execute()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php index 5372bb11a89b5..c52d5b2fb370f 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php @@ -5,7 +5,6 @@ */ namespace Magento\Customer\Test\Unit\Controller\Adminhtml\Index; -use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Api\CustomerMetadataInterface; use Magento\Customer\Api\Data\AttributeMetadataInterface; use Magento\Customer\Api\Data\CustomerInterface; @@ -281,7 +280,6 @@ protected function setUp() public function testExecuteWithExistentCustomer() { $customerId = 22; - $addressId = 11; $subscription = 'true'; $postValue = [ 'customer' => [ @@ -290,18 +288,6 @@ public function testExecuteWithExistentCustomer() 'coolness' => false, 'disable_auto_group_change' => 'false', ], - 'address' => [ - '_template_' => '_template_', - $addressId => [ - 'entity_id' => $addressId, - 'default_billing' => 'true', - 'default_shipping' => 'true', - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ], - ], 'subscription' => $subscription, ]; $extractedData = [ @@ -318,22 +304,6 @@ public function testExecuteWithExistentCustomer() CustomerInterface::DEFAULT_BILLING => 2, CustomerInterface::DEFAULT_SHIPPING => 2 ]; - $addressExtractedData = [ - 'entity_id' => $addressId, - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; - $addressCompactedData = [ - 'entity_id' => $addressId, - 'default_billing' => 'true', - 'default_shipping' => 'true', - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; $savedData = [ 'entity_id' => $customerId, 'darkness' => true, @@ -341,61 +311,40 @@ public function testExecuteWithExistentCustomer() CustomerInterface::DEFAULT_BILLING => false, CustomerInterface::DEFAULT_SHIPPING => false, ]; - $savedAddressData = [ - 'entity_id' => $addressId, - 'default_billing' => true, - 'default_shipping' => true, - ]; $mergedData = [ 'entity_id' => $customerId, 'darkness' => true, 'name' => 'Name', 'code' => 'value', 'disable_auto_group_change' => 0, - CustomerInterface::DEFAULT_BILLING => $addressId, - CustomerInterface::DEFAULT_SHIPPING => $addressId, 'confirmation' => false, 'sendemail_store_id' => '1', 'id' => $customerId, ]; - $mergedAddressData = [ - 'entity_id' => $addressId, - 'default_billing' => true, - 'default_shipping' => true, - 'code' => 'value', - 'region' => [ - 'region' => 'region', - 'region_id' => 'region_id', - ], - 'region_id' => 'region_id', - 'id' => $addressId, - ]; /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ $attributeMock = $this->getMockBuilder( \Magento\Customer\Api\Data\AttributeMetadataInterface::class )->disableOriginalConstructor()->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; - $this->requestMock->expects($this->any()) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPostValue') ->willReturnMap([ [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ]); - $this->requestMock->expects($this->exactly(3)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, $postValue['address']], ['subscription', null, $subscription], ] ); @@ -404,16 +353,15 @@ public function testExecuteWithExistentCustomer() $objectMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->atLeastOnce()) ->method('getData') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ] ); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->exactly(1)) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -432,23 +380,7 @@ public function testExecuteWithExistentCustomer() $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); - - $customerAddressFormMock = $this->getMockBuilder( - \Magento\Customer\Model\Metadata\Form::class - )->disableOriginalConstructor()->getMock(); - $customerAddressFormMock->expects($this->once()) - ->method('extractData') - ->with($this->requestMock, 'address/' . $addressId) - ->willReturn($addressExtractedData); - $customerAddressFormMock->expects($this->once()) - ->method('compactData') - ->with($addressExtractedData) - ->willReturn($addressCompactedData); - $customerAddressFormMock->expects($this->once()) - ->method('getAttributes') - ->willReturn($attributes); - - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->exactly(1)) ->method('create') ->willReturnMap( [ @@ -461,15 +393,6 @@ public function testExecuteWithExistentCustomer() [], $customerFormMock ], - [ - AddressMetadataInterface::ENTITY_TYPE_ADDRESS, - 'adminhtml_customer_address', - $savedAddressData, - false, - Form::DONT_IGNORE_INVISIBLE, - [], - $customerAddressFormMock - ], ] ); @@ -492,25 +415,7 @@ public function testExecuteWithExistentCustomer() ->with($customerMock) ->willReturn($savedData); - $addressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->customerAddressRepositoryMock->expects($this->once()) - ->method('getById') - ->with($addressId) - ->willReturn($addressMock); - - $this->customerAddressMapperMock->expects($this->once()) - ->method('toFlatArray') - ->with($addressMock) - ->willReturn($savedAddressData); - - $this->addressDataFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($addressMock); - - $this->dataHelperMock->expects($this->exactly(2)) + $this->dataHelperMock->expects($this->atLeastOnce()) ->method('populateWithArray') ->willReturnMap( [ @@ -519,19 +424,9 @@ public function testExecuteWithExistentCustomer() $mergedData, \Magento\Customer\Api\Data\CustomerInterface::class, $this->dataHelperMock ], - [ - $addressMock, - $mergedAddressData, \Magento\Customer\Api\Data\AddressInterface::class, - $this->dataHelperMock - ], ] ); - $customerMock->expects($this->once()) - ->method('setAddresses') - ->with([$addressMock]) - ->willReturnSelf(); - $this->customerRepositoryMock->expects($this->once()) ->method('save') ->with($customerMock) @@ -608,63 +503,33 @@ public function testExecuteWithExistentCustomer() public function testExecuteWithNewCustomer() { $customerId = 22; - $addressId = 11; + $subscription = '0'; $postValue = [ 'customer' => [ 'coolness' => false, 'disable_auto_group_change' => 'false', ], - 'address' => [ - '_template_' => '_template_', - $addressId => [ - 'entity_id' => $addressId, - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ], - ], 'subscription' => $subscription, ]; $extractedData = [ 'coolness' => false, 'disable_auto_group_change' => 'false', ]; - $addressExtractedData = [ - 'entity_id' => $addressId, - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; $mergedData = [ 'disable_auto_group_change' => 0, CustomerInterface::DEFAULT_BILLING => null, CustomerInterface::DEFAULT_SHIPPING => null, 'confirmation' => false, ]; - $mergedAddressData = [ - 'entity_id' => $addressId, - 'default_billing' => false, - 'default_shipping' => false, - 'code' => 'value', - 'region' => [ - 'region' => 'region', - 'region_id' => 'region_id', - ], - 'region_id' => 'region_id', - 'id' => $addressId, - ]; - /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ $attributeMock = $this->getMockBuilder( \Magento\Customer\Api\Data\AttributeMetadataInterface::class )->disableOriginalConstructor()->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; @@ -674,14 +539,12 @@ public function testExecuteWithNewCustomer() ->willReturnMap([ [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ]); - $this->requestMock->expects($this->exactly(3)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, $postValue['address']], ['subscription', null, $subscription], ] ); @@ -690,16 +553,15 @@ public function testExecuteWithNewCustomer() $objectMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->atLeastOnce()) ->method('getData') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ] ); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->atLeastOnce()) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -719,22 +581,7 @@ public function testExecuteWithNewCustomer() ->method('getAttributes') ->willReturn($attributes); - $customerAddressFormMock = $this->getMockBuilder( - \Magento\Customer\Model\Metadata\Form::class - )->disableOriginalConstructor()->getMock(); - $customerAddressFormMock->expects($this->once()) - ->method('extractData') - ->with($this->requestMock, 'address/' . $addressId) - ->willReturn($addressExtractedData); - $customerAddressFormMock->expects($this->once()) - ->method('compactData') - ->with($addressExtractedData) - ->willReturn($addressExtractedData); - $customerAddressFormMock->expects($this->once()) - ->method('getAttributes') - ->willReturn($attributes); - - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->exactly(1)) ->method('create') ->willReturnMap( [ @@ -747,15 +594,6 @@ public function testExecuteWithNewCustomer() [], $customerFormMock ], - [ - AddressMetadataInterface::ENTITY_TYPE_ADDRESS, - 'adminhtml_customer_address', - [], - false, - Form::DONT_IGNORE_INVISIBLE, - [], - $customerAddressFormMock - ], ] ); @@ -768,25 +606,7 @@ public function testExecuteWithNewCustomer() ->method('create') ->willReturn($customerMock); - $addressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->addressDataFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($addressMock); - - $this->customerAddressRepositoryMock->expects($this->once()) - ->method('getById') - ->with($addressId) - ->willReturn($addressMock); - - $this->customerAddressMapperMock->expects($this->once()) - ->method('toFlatArray') - ->with($addressMock) - ->willReturn([]); - - $this->dataHelperMock->expects($this->exactly(2)) + $this->dataHelperMock->expects($this->atLeastOnce()) ->method('populateWithArray') ->willReturnMap( [ @@ -795,11 +615,6 @@ public function testExecuteWithNewCustomer() $mergedData, \Magento\Customer\Api\Data\CustomerInterface::class, $this->dataHelperMock ], - [ - $addressMock, - $mergedAddressData, \Magento\Customer\Api\Data\AddressInterface::class, - $this->dataHelperMock - ], ] ); @@ -904,12 +719,11 @@ public function testExecuteWithNewCustomerAndValidationException() [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], ]); - $this->requestMock->expects($this->exactly(2)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, null], ] ); @@ -1047,12 +861,11 @@ public function testExecuteWithNewCustomerAndLocalizedException() [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], ]); - $this->requestMock->expects($this->exactly(2)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, null], ] ); @@ -1190,12 +1003,11 @@ public function testExecuteWithNewCustomerAndException() [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], ]); - $this->requestMock->expects($this->exactly(2)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, null], ] ); diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php index 7209ac9fd24b0..5adb902601630 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php @@ -141,12 +141,6 @@ protected function setUp() public function testExecute() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn([ - '_template_' => null, - 'address_index' => null - ]); $customerEntityId = 2; $this->request->expects($this->once()) ->method('getParam') @@ -162,11 +156,6 @@ public function testExecute() $this->form->expects($this->once())->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce())->method('extractData')->willReturn([]); - $error = $this->createMock(\Magento\Framework\Message\Error::class); - $this->form->expects($this->once()) - ->method('validateData') - ->willReturn([$error]); - $validationResult = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\ValidationResultsInterface::class, [], @@ -188,9 +177,6 @@ public function testExecute() public function testExecuteWithoutAddresses() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn(null); $this->form->expects($this->once()) ->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce()) @@ -223,9 +209,6 @@ public function testExecuteWithoutAddresses() public function testExecuteWithException() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn(null); $this->form->expects($this->once()) ->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce()) @@ -265,12 +248,6 @@ public function testExecuteWithException() public function testExecuteWithNewCustomerAndNoEntityId() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn([ - '_template_' => null, - 'address_index' => null - ]); $this->request->expects($this->once()) ->method('getParam') ->with('customer') @@ -282,11 +259,6 @@ public function testExecuteWithNewCustomerAndNoEntityId() $this->form->expects($this->once())->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce())->method('extractData')->willReturn([]); - $error = $this->createMock(\Magento\Framework\Message\Error::class); - $this->form->expects($this->once()) - ->method('validateData') - ->willReturn([$error]); - $validationResult = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\ValidationResultsInterface::class, [], diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php new file mode 100644 index 0000000000000..815a47288e370 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -0,0 +1,233 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Test\Unit\Model\Address; + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Customer\Model\ResourceModel\Address\Collection as AddressCollection; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Type; +use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Customer\Model\Attribute as AttributeModel; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Customer\Model\Address as AddressModel; +use Magento\Customer\Model\FileProcessorFactory; + +class DataProviderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressCollectionFactory; + + /** + * @var AddressCollection|\PHPUnit_Framework_MockObject_MockObject + */ + private $collection; + + /** + * @var CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $customerRepository; + + /** + * @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $customer; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + private $eavConfig; + + /** + * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject + */ + private $eavValidationRules; + + /* + * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $context; + + /** + * @var \Magento\Customer\Model\Config\Share|\PHPUnit_Framework_MockObject_MockObject + */ + private $shareConfig; + + /** + * @var FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileProcessorFactory; + + /** + * @var Type|\PHPUnit_Framework_MockObject_MockObject + */ + private $entityType; + + /** + * @var AddressModel|\PHPUnit_Framework_MockObject_MockObject + */ + private $address; + + /** + * @var AttributeModel|\PHPUnit_Framework_MockObject_MockObject + */ + private $attribute; + + /** + * @var \Magento\Customer\Model\Address\DataProvider + */ + private $model; + + protected function setUp() + { + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->addressCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->collection = $this->getMockBuilder(AddressCollection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerRepository = $this->getMockForAbstractClass(CustomerRepositoryInterface::class); + $this->eavValidationRules = $this->createMock(EavValidationRules::class); + $this->context = $this->getMockForAbstractClass(ContextInterface::class); + $this->fileProcessorFactory = $this->getMockBuilder(FileProcessorFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->shareConfig = $this->createMock(\Magento\Customer\Model\Config\Share::class); + $this->addressCollectionFactory->expects($this->once()) + ->method('create') + ->willReturn($this->collection); + $this->eavConfig = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->entityType = $this->getMockBuilder(Type::class) + ->disableOriginalConstructor() + ->getMock(); + $this->entityType->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn([]); + $this->eavConfig->expects($this->once()) + ->method('getEntityType') + ->willReturn($this->entityType); + $this->customer = $this->getMockForAbstractClass(CustomerInterface::class); + $this->address = $this->getMockBuilder(AddressModel::class) + ->disableOriginalConstructor() + ->getMock(); + $this->attribute = $this->getMockBuilder(AttributeModel::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = $objectManagerHelper->getObject( + \Magento\Customer\Model\Address\DataProvider::class, + [ + '', + '', + '', + 'addressCollectionFactory' => $this->addressCollectionFactory, + 'customerRepository' => $this->customerRepository, + 'eavConfig' => $this->eavConfig, + 'eavValidationRules' => $this->eavValidationRules, + 'context' => $this->context, + 'fileProcessorFactory' => $this->fileProcessorFactory, + 'shareConfig' => $this->shareConfig, + [], + [], + true + ] + ); + } + + public function testGetDefaultData() + { + $expectedData = [ + '' => [ + 'parent_id' => 1, + 'firstname' => 'John', + 'lastname' => 'Doe' + ] + ]; + + $this->collection->expects($this->once()) + ->method('getItems') + ->willReturn([]); + + $this->context->expects($this->once()) + ->method('getRequestParam') + ->willReturn(1); + $this->customerRepository->expects($this->once()) + ->method('getById') + ->willReturn($this->customer); + $this->customer->expects($this->once()) + ->method('getFirstname') + ->willReturn('John'); + $this->customer->expects($this->once()) + ->method('getLastname') + ->willReturn('Doe'); + + $this->assertEquals($expectedData, $this->model->getData()); + } + + public function testGetData() + { + $expectedData = [ + '3' => [ + 'parent_id' => "1", + 'firstname' => 'John', + 'lastname' => 'Doe', + 'street' => [ + '42000 Ave W 55 Cedar City', + 'Apt. 33' + ] + ] + ]; + + $this->collection->expects($this->once()) + ->method('getItems') + ->willReturn([ + $this->address + ]); + + $this->customerRepository->expects($this->once()) + ->method('getById') + ->willReturn($this->customer); + $this->customer->expects($this->once()) + ->method('getDefaultBilling') + ->willReturn('1'); + $this->customer->expects($this->once()) + ->method('getDefaultShipping') + ->willReturn('1'); + + $this->address->expects($this->once()) + ->method('getEntityId') + ->willReturn('3'); + $this->address->expects($this->once()) + ->method('load') + ->with("3") + ->willReturnSelf(); + $this->address->expects($this->once()) + ->method('getData') + ->willReturn([ + 'parent_id' => "1", + 'firstname' => "John", + 'lastname' => 'Doe', + 'street' => "42000 Ave W 55 Cedar City\nApt. 33" + ]); + $this->address->expects($this->once()) + ->method('getAttributes') + ->willReturn([$this->attribute]); + $this->attribute->expects($this->once()) + ->method('getFrontendInput') + ->willReturn(null); + + $this->assertEquals($expectedData, $this->model->getData()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php new file mode 100644 index 0000000000000..eb1241de3e32c --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php @@ -0,0 +1,1065 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Unit\Model\Customer; + +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Model\Config\Share; +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Eav\Model\Entity\Type; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Ui\Component\Form\Field; +use Magento\Ui\DataProvider\EavValidationRules; + +/** + * Class DataProviderTest + * + * Test for class \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class DataProviderWithDefaultAddressesTest extends \PHPUnit\Framework\TestCase +{ + const ATTRIBUTE_CODE = 'test-code'; + const OPTIONS_RESULT = 'test-options'; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavConfigMock; + + /** + * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $customerCollectionFactoryMock; + + /** + * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavValidationRulesMock; + + /** + * @var \Magento\Framework\Session\SessionManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $sessionMock; + + /** + * @var \Magento\Customer\Model\FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fileProcessorFactory; + + /** + * @var \Magento\Customer\Model\FileProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fileProcessor; + + /** + * @var \Magento\Directory\Model\CountryFactory + */ + private $countryFactoryMock; + + /** + * @var \Magento\Customer\Model\Customer + */ + private $customerMock; + + /** + * @var \Magento\Customer\Model\ResourceModel\Customer\Collection + */ + private $customerCollectionMock; + + /** + * @var \Magento\Customer\Model\Config\Share + */ + private $shareConfigMock; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsitesMock; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->eavConfigMock = $this->getMockBuilder(\Magento\Eav\Model\Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionFactoryMock = $this->createPartialMock( + \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory::class, + ['create'] + ); + $this->eavValidationRulesMock = $this + ->getMockBuilder(\Magento\Ui\DataProvider\EavValidationRules::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this + ->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) + ->setMethods(['getCustomerFormData', 'unsCustomerFormData']) + ->getMockForAbstractClass(); + + $this->fileProcessor = $this->getMockBuilder(\Magento\Customer\Model\FileProcessor::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileProcessorFactory = $this->getMockBuilder(\Magento\Customer\Model\FileProcessorFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->countryFactoryMock = $this->getMockBuilder(\Magento\Directory\Model\CountryFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create', 'loadByCode', 'getName']) + ->getMock(); + + $this->customerMock = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionMock = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Customer\Collection::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionMock->expects($this->any())->method('addAttributeToSelect')->with('*'); + $this->customerCollectionFactoryMock + ->expects($this->any()) + ->method('create') + ->willReturn($this->customerCollectionMock); + + $this->eavConfigMock->expects($this->at(0)) + ->method('getEntityType') + ->with('customer') + ->willReturn($this->getTypeCustomerMock([])); + $this->eavConfigMock->expects($this->at(1)) + ->method('getEntityType') + ->with('customer_address') + ->willReturn($this->getTypeAddressMock()); + + $this->shareConfigMock = $this->getMockBuilder(\Magento\Customer\Model\Config\Share::class) + ->disableOriginalConstructor() + ->getMock(); + $this->countryWithWebsitesMock = $this->getMockBuilder(CountryWithWebsites::class) + ->disableOriginalConstructor() + ->setMethods(['getAllOptions']) + ->getMock(); + $this->countryWithWebsitesMock->expects($this->any())->method('getAllOptions')->willReturn('test-options'); + + $helper = new ObjectManager($this); + $this->dataProvider = $helper->getObject( + \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses::class, + [ + 'name' => 'test-name', + 'primaryFieldName' => 'primary-field-name', + 'requestFieldName' => 'request-field-name', + 'eavValidationRules' => $this->eavValidationRulesMock, + 'customerCollectionFactory' => $this->customerCollectionFactoryMock, + 'eavConfig' => $this->eavConfigMock, + 'countryFactory' => $this->countryFactoryMock, + 'session' => $this->sessionMock, + 'fileProcessorFactory' => $this->fileProcessorFactory, + 'shareConfig' => $this->shareConfigMock, + 'countryWithWebsites' => $this->countryWithWebsitesMock, + ] + ); + } + + /** + * Run test getAttributesMeta method + * + * @param array $expected + * @return void + * + * @dataProvider getAttributesMetaDataProvider + */ + public function testGetAttributesMetaWithOptions(array $expected) + { + $meta = $this->dataProvider->getMeta(); + $this->assertNotEmpty($meta); + $this->assertEquals($expected, $meta); + } + + /** + * Data provider for testGetAttributesMeta + * + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getAttributesMetaDataProvider() + { + return [ + [ + 'expected' => [ + 'customer' => [ + 'children' => [ + self::ATTRIBUTE_CODE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + ], + ], + 'address' => [ + 'children' => [ + self::ATTRIBUTE_CODE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => null, + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + 'country_id' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'filterBy' => [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ] + ], + ], + ], + ] + ], + ], + ] + ] + ]; + } + + /** + * @return CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getCustomerCollectionFactoryMock() + { + $collectionMock = $this->getMockBuilder(\Magento\Customer\Model\ResourceModel\Customer\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + + $collectionMock->expects($this->any()) + ->method('addAttributeToSelect') + ->with('*'); + + $this->customerCollectionFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($collectionMock); + + return $this->customerCollectionFactoryMock; + } + + /** + * @return Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getEavConfigMock($customerAttributes = []) + { + $this->eavConfigMock->expects($this->at(0)) + ->method('getEntityType') + ->with('customer') + ->willReturn($this->getTypeCustomerMock($customerAttributes)); + $this->eavConfigMock->expects($this->at(1)) + ->method('getEntityType') + ->with('customer_address') + ->willReturn($this->getTypeAddressMock()); + + return $this->eavConfigMock; + } + + /** + * @return Type|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypeCustomerMock($customerAttributes = []) + { + $typeCustomerMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + $attributesCollection = !empty($customerAttributes) ? $customerAttributes : $this->getAttributeMock(); + $typeCustomerMock->expects($this->any()) + ->method('getEntityTypeCode') + ->willReturn('customer'); + foreach ($attributesCollection as $attribute) { + $attribute->expects($this->any()) + ->method('getEntityType') + ->willReturn($typeCustomerMock); + } + + $typeCustomerMock->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn($attributesCollection); + + return $typeCustomerMock; + } + + /** + * @return Type|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypeAddressMock() + { + $typeAddressMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + + $typeAddressMock->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn($this->getAttributeMock('address')); + + return $typeAddressMock; + } + + /** + * @param \PHPUnit_Framework_MockObject_MockObject $attributeMock + * @param \PHPUnit_Framework_MockObject_MockObject $attributeBooleanMock + * @param array $options + */ + private function injectVisibilityProps( + \PHPUnit_Framework_MockObject_MockObject $attributeMock, + \PHPUnit_Framework_MockObject_MockObject $attributeBooleanMock, + array $options = [] + ) { + if (isset($options[self::ATTRIBUTE_CODE]['visible'])) { + $attributeMock->expects($this->any()) + ->method('getIsVisible') + ->willReturn($options[self::ATTRIBUTE_CODE]['visible']); + } + + if (isset($options[self::ATTRIBUTE_CODE]['user_defined'])) { + $attributeMock->expects($this->any()) + ->method('getIsUserDefined') + ->willReturn($options[self::ATTRIBUTE_CODE]['user_defined']); + } + + if (isset($options[self::ATTRIBUTE_CODE]['is_used_in_forms'])) { + $attributeMock->expects($this->any()) + ->method('getUsedInForms') + ->willReturn($options[self::ATTRIBUTE_CODE]['is_used_in_forms']); + } + + if (isset($options['test-code-boolean']['visible'])) { + $attributeBooleanMock->expects($this->any()) + ->method('getIsVisible') + ->willReturn($options['test-code-boolean']['visible']); + } + + if (isset($options['test-code-boolean']['user_defined'])) { + $attributeBooleanMock->expects($this->any()) + ->method('getIsUserDefined') + ->willReturn($options['test-code-boolean']['user_defined']); + } + + if (isset($options['test-code-boolean']['is_used_in_forms'])) { + $attributeBooleanMock->expects($this->any()) + ->method('getUsedInForms') + ->willReturn($options['test-code-boolean']['is_used_in_forms']); + } + } + + /** + * @return AbstractAttribute[]|\PHPUnit_Framework_MockObject_MockObject[] + */ + protected function getAttributeMock($type = 'customer', $options = []) + { + $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods( + [ + 'getAttributeCode', + 'getDataUsingMethod', + 'usesSource', + 'getFrontendInput', + 'getIsVisible', + 'getSource', + 'getIsUserDefined', + 'getUsedInForms', + 'getEntityType', + ] + ) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $sourceMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Source\AbstractSource::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $attributeCode = self::ATTRIBUTE_CODE; + if (isset($options[self::ATTRIBUTE_CODE]['specific_code_prefix'])) { + $attributeCode .= $options[self::ATTRIBUTE_CODE]['specific_code_prefix']; + } + + $attributeMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn($attributeCode); + + $sourceMock->expects($this->any()) + ->method('getAllOptions') + ->willReturn(self::OPTIONS_RESULT); + + $attributeMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback($this->attributeGetUsingMethodCallback()); + + $attributeMock->expects($this->any()) + ->method('usesSource') + ->willReturn(true); + $attributeMock->expects($this->any()) + ->method('getSource') + ->willReturn($sourceMock); + + $attributeBooleanMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods( + [ + 'getAttributeCode', + 'getDataUsingMethod', + 'usesSource', + 'getFrontendInput', + 'getIsVisible', + 'getIsUserDefined', + 'getUsedInForms', + 'getSource', + 'getEntityType', + ] + ) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $attributeBooleanMock->expects($this->any()) + ->method('getFrontendInput') + ->willReturn('boolean'); + $attributeBooleanMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback($this->attributeGetUsingMethodCallback()); + + $attributeBooleanMock->expects($this->once()) + ->method('usesSource') + ->willReturn(false); + $booleanAttributeCode = 'test-code-boolean'; + if (isset($options['test-code-boolean']['specific_code_prefix'])) { + $booleanAttributeCode .= $options['test-code-boolean']['specific_code_prefix']; + } + + $attributeBooleanMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn($booleanAttributeCode); + + $this->eavValidationRulesMock->expects($this->any()) + ->method('build') + ->willReturnMap([ + [$attributeMock, $this->logicalNot($this->isEmpty()), []], + [$attributeBooleanMock, $this->logicalNot($this->isEmpty()), []], + ]); + $mocks = [$attributeMock, $attributeBooleanMock]; + $this->injectVisibilityProps($attributeMock, $attributeBooleanMock, $options); + if ($type == "address") { + $mocks[] = $this->getCountryAttrMock(); + } + return $mocks; + } + + /** + * Callback for ::getDataUsingMethod + * + * @return \Closure + */ + private function attributeGetUsingMethodCallback() + { + return function ($origName) { + return $origName; + }; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getCountryAttrMock() + { + $objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class); + $objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap([ + [CountryWithWebsites::class, $this->countryWithWebsitesMock], + [Share::class, $this->shareConfigMock], + ]); + \Magento\Framework\App\ObjectManager::setInstance($objectManagerMock); + $countryAttrMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods(['getAttributeCode', 'getDataUsingMethod', 'usesSource', 'getSource', 'getLabel']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $countryAttrMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn('country_id'); + + $countryAttrMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback( + function ($origName) { + return $origName; + } + ); + $countryAttrMock->expects($this->any()) + ->method('getLabel') + ->willReturn(__('frontend_label')); + $countryAttrMock->expects($this->any()) + ->method('usesSource') + ->willReturn(true); + $countryAttrMock->expects($this->any()) + ->method('getSource') + ->willReturn(null); + + return $countryAttrMock; + } + + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetData() + { + $customerData = [ + 'email' => 'test@test.ua', + 'default_billing' => 2, + 'default_shipping' => 2, + 'password_hash' => 'password_hash', + 'rp_token' => 'rp_token', + 'confirmation' => 'confirmation', + ]; + + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class)->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionMock->expects($this->once())->method('getItems')->willReturn([$this->customerMock]); + $this->customerMock->expects($this->once())->method('getData')->willReturn($customerData); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([]); + + $this->customerMock->expects($this->once())->method('getDefaultBillingAddress')->willReturn($address); + $this->countryFactoryMock->expects($this->once())->method('create')->willReturnSelf(); + $this->countryFactoryMock->expects($this->once())->method('loadByCode')->willReturnSelf(); + $this->countryFactoryMock->expects($this->once())->method('getName')->willReturn('Ukraine'); + + $this->sessionMock->expects($this->once()) + ->method('getCustomerFormData') + ->willReturn(null); + + $this->assertEquals( + [ + '' => [ + 'customer' => [ + 'email' => 'test@test.ua', + 'default_billing' => 2, + 'default_shipping' => 2, + ], + 'default_billing_address' => [ + 'country' => 'Ukraine', + ], + 'default_shipping_address' => [] + ] + ], + $this->dataProvider->getData() + ); + } + + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetDataWithCustomerFormData() + { + $customerId = 11; + $customerFormData = [ + 'customer' => [ + 'email' => 'test1@test1.ua', + 'default_billing' => 3, + 'default_shipping' => 3, + 'entity_id' => $customerId, + ], + 'address' => [ + 3 => [ + 'firstname' => 'firstname1', + 'lastname' => 'lastname1', + 'street' => [ + 'street1', + 'street2', + ], + 'default_billing' => 3, + 'default_shipping' => 3, + ], + ], + ]; + + $this->customerCollectionMock->expects($this->once())->method('getItems')->willReturn([$this->customerMock]); + $this->customerMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'email' => 'test@test.ua', + 'default_billing' => 2, + 'default_shipping' => 2, + ]); + $this->customerMock->expects($this->once())->method('getId')->willReturn($customerId); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([]); + + $this->sessionMock->expects($this->once())->method('getCustomerFormData')->willReturn($customerFormData); + $this->sessionMock->expects($this->once())->method('unsCustomerFormData'); + + $this->assertEquals([$customerId => $customerFormData], $this->dataProvider->getData()); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @return void + */ + public function testGetDataWithCustomAttributeImage() + { + $customerId = 1; + $customerEmail = 'user1@example.com'; + + $filename = '/filename.ext1'; + $viewUrl = 'viewUrl'; + $mime = 'image/png'; + + $expectedData = [ + $customerId => [ + 'customer' => [ + 'email' => $customerEmail, + 'img1' => [ + [ + 'file' => $filename, + 'size' => 1, + 'url' => $viewUrl, + 'name' => 'filename.ext1', + 'type' => $mime, + ], + ], + ], + 'default_billing_address' => [], + 'default_shipping_address' => [], + ], + ]; + + $attributeMock = $this->getMockBuilder(\Magento\Customer\Model\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock->expects($this->exactly(2)) + ->method('getFrontendInput') + ->willReturn('image'); + $attributeMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn('img1'); + + $entityTypeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + $entityTypeMock->expects($this->once()) + ->method('getEntityTypeCode') + ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); + + $this->customerMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'email' => $customerEmail, + 'img1' => $filename, + ]); + $this->customerMock->expects($this->once())->method('getId')->willReturn($customerId); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([$attributeMock]); + $this->customerMock->expects($this->once())->method('getEntityType')->willReturn($entityTypeMock); + $this->customerCollectionMock->expects($this->any())->method('getItems')->willReturn([$this->customerMock]); + $this->sessionMock->expects($this->once())->method('getCustomerFormData')->willReturn([]); + $this->fileProcessorFactory->expects($this->any()) + ->method('create') + ->with([ + 'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, + ]) + ->willReturn($this->fileProcessor); + $this->fileProcessor->expects($this->once())->method('isExist')->with($filename)->willReturn(true); + $this->fileProcessor->expects($this->once())->method('getStat')->with($filename)->willReturn(['size' => 1]); + $this->fileProcessor->expects($this->once())->method('getViewUrl') + ->with('/filename.ext1', 'image') + ->willReturn($viewUrl); + $this->fileProcessor->expects($this->once())->method('getMimeType')->with($filename)->willReturn($mime); + + $objectManager = new ObjectManager($this); + + $objectManager->setBackwardCompatibleProperty( + $this->dataProvider, + 'fileProcessorFactory', + $this->fileProcessorFactory + ); + + $this->assertEquals($expectedData, $this->dataProvider->getData()); + } + + public function testGetDataWithCustomAttributeImageNoData() + { + $customerId = 1; + $customerEmail = 'user1@example.com'; + + $expectedData = [ + $customerId => [ + 'customer' => [ + 'email' => $customerEmail, + 'img1' => [], + ], + 'default_billing_address' => [], + 'default_shipping_address' => [], + ], + ]; + + $attributeMock = $this->getMockBuilder(\Magento\Customer\Model\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock->expects($this->once()) + ->method('getFrontendInput') + ->willReturn('image'); + $attributeMock->expects($this->exactly(2))->method('getAttributeCode') + ->willReturn('img1'); + + $entityTypeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + $entityTypeMock->expects($this->once()) + ->method('getEntityTypeCode') + ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); + + $this->customerMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'email' => $customerEmail, + ]); + $this->customerMock->expects($this->once())->method('getId')->willReturn($customerId); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([$attributeMock]); + $this->customerMock->expects($this->once())->method('getEntityType')->willReturn($entityTypeMock); + $this->customerCollectionMock->expects($this->any())->method('getItems')->willReturn([$this->customerMock]); + $this->sessionMock->expects($this->once())->method('getCustomerFormData')->willReturn([]); + + $this->assertEquals($expectedData, $this->dataProvider->getData()); + } + + /** + * @return void + */ + public function testGetDataWithVisibleAttributes() + { + $firstAttributesBundle = $this->getAttributeMock( + 'customer', + [ + self::ATTRIBUTE_CODE => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_edit'], + 'user_defined' => true, + 'specific_code_prefix' => "_1" + ], + 'test-code-boolean' => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_create'], + 'user_defined' => true, + 'specific_code_prefix' => "_1" + ] + ] + ); + $secondAttributesBundle = $this->getAttributeMock( + 'customer', + [ + self::ATTRIBUTE_CODE => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_create'], + 'user_defined' => false, + 'specific_code_prefix' => "_2" + ], + 'test-code-boolean' => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_create'], + 'user_defined' => true, + 'specific_code_prefix' => "_2" + ] + ] + ); + + $helper = new ObjectManager($this); + /** @var \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses $dataProvider */ + $dataProvider = $helper->getObject( + \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses::class, + [ + 'name' => 'test-name', + 'primaryFieldName' => 'primary-field-name', + 'requestFieldName' => 'request-field-name', + 'eavValidationRules' => $this->eavValidationRulesMock, + 'customerCollectionFactory' => $this->getCustomerCollectionFactoryMock(), + 'eavConfig' => $this->getEavConfigMock(array_merge($firstAttributesBundle, $secondAttributesBundle)) + ] + ); + + $helper->setBackwardCompatibleProperty( + $dataProvider, + 'fileProcessorFactory', + $this->fileProcessorFactory + ); + + $meta = $dataProvider->getMeta(); + $this->assertNotEmpty($meta); + $this->assertEquals($this->getExpectationForVisibleAttributes(), $meta); + } + + /** + * Retrieve all customer variations of attributes with all variations of visibility + * + * @param bool $isRegistration + * @return array + */ + private function getCustomerAttributeExpectations($isRegistration) + { + return [ + self::ATTRIBUTE_CODE . "_1" => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => !$isRegistration, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + self::ATTRIBUTE_CODE . "_2" => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => true, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean_1' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => $isRegistration, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + 'test-code-boolean_2' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => $isRegistration, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + ]; + } + + /** + * Retrieve all variations of attributes with all variations of visibility + * + * @param bool $isRegistration + * @return array + */ + private function getExpectationForVisibleAttributes($isRegistration = true) + { + return [ + 'customer' => [ + 'children' => $this->getCustomerAttributeExpectations($isRegistration), + ], + 'address' => [ + 'children' => [ + self::ATTRIBUTE_CODE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => null, + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + 'country_id' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => null, + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'filterBy' => [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ] + ], + ], + ], + ] + ], + ], + ]; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index a142f87dcf6c4..1d262e7549873 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -195,35 +195,6 @@ public function testSave() $customerId = 1; $storeId = 2; - $region = $this->getMockForAbstractClass(\Magento\Customer\Api\Data\RegionInterface::class, [], '', false); - $address = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); - $address2 = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); $customerModel = $this->createPartialMock(\Magento\Customer\Model\Customer::class, [ 'getId', 'setId', @@ -243,10 +214,6 @@ public function testSave() $origCustomer = $this->customer; - $this->customer->expects($this->atLeastOnce()) - ->method('__toArray') - ->willReturn(['default_billing', 'default_shipping']); - $customerAttributesMetaData = $this->getMockForAbstractClass( \Magento\Framework\Api\CustomAttributesDataInterface::class, [], @@ -258,8 +225,6 @@ public function testSave() 'getId', 'getEmail', 'getWebsiteId', - 'getAddresses', - 'setAddresses' ] ); $customerSecureData = $this->createPartialMock(\Magento\Customer\Model\Data\CustomerSecure::class, [ @@ -287,28 +252,6 @@ public function testSave() $this->customerRegistry->expects($this->atLeastOnce()) ->method("remove") ->with($customerId); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId) - ->willReturnSelf(); - $address->expects($this->once()) - ->method('getRegion') - ->willReturn($region); - $address->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(7); - $address->expects($this->once()) - ->method('setRegion') - ->with($region); - $customerAttributesMetaData->expects($this->atLeastOnce()) - ->method('getAddresses') - ->willReturn([$address]); - $customerAttributesMetaData->expects($this->at(1)) - ->method('setAddresses') - ->with([]); - $customerAttributesMetaData->expects($this->at(2)) - ->method('setAddresses') - ->with([$address]); $this->extensibleDataObjectConverter->expects($this->once()) ->method('toNestedArray') ->with($customerAttributesMetaData, [], \Magento\Customer\Api\Data\CustomerInterface::class) @@ -393,12 +336,6 @@ public function testSave() $this->customerRegistry->expects($this->once()) ->method('push') ->with($customerModel); - $this->customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address, $address2]); - $this->addressRepository->expects($this->once()) - ->method('save') - ->with($address); $customerAttributesMetaData->expects($this->once()) ->method('getEmail') ->willReturn('example@example.com'); @@ -446,41 +383,8 @@ public function testSaveWithPasswordHash() '', false ); - $address = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); - $address2 = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); - $origCustomer = $this->customer; - $this->customer->expects($this->atLeastOnce()) - ->method('__toArray') - ->willReturn(['default_billing', 'default_shipping']); - $customerModel = $this->createPartialMock(\Magento\Customer\Model\Customer::class, [ 'getId', 'setId', @@ -505,8 +409,6 @@ public function testSaveWithPasswordHash() 'getId', 'getEmail', 'getWebsiteId', - 'getAddresses', - 'setAddresses' ] ); $customerModel->expects($this->atLeastOnce()) @@ -559,28 +461,6 @@ public function testSaveWithPasswordHash() ->method('save') ->with($this->customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $this->customer) ->willReturn($customerAttributesMetaData); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId) - ->willReturnSelf(); - $address->expects($this->once()) - ->method('getRegion') - ->willReturn($region); - $address->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(7); - $address->expects($this->once()) - ->method('setRegion') - ->with($region); - $customerAttributesMetaData->expects($this->any()) - ->method('getAddresses') - ->willReturn([$address]); - $customerAttributesMetaData->expects($this->at(1)) - ->method('setAddresses') - ->with([]); - $customerAttributesMetaData->expects($this->at(2)) - ->method('setAddresses') - ->with([$address]); $customerAttributesMetaData ->expects($this->atLeastOnce()) ->method('getId') @@ -618,12 +498,6 @@ public function testSaveWithPasswordHash() $this->customerRegistry->expects($this->once()) ->method('push') ->with($customerModel); - $this->customer->expects($this->any()) - ->method('getAddresses') - ->willReturn([$address, $address2]); - $this->addressRepository->expects($this->once()) - ->method('save') - ->with($address); $customerAttributesMetaData->expects($this->once()) ->method('getEmail') ->willReturn('example@example.com'); diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php new file mode 100644 index 0000000000000..82ce4249bcd85 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Ui\Test\Unit\Component\Form; + +use Magento\Customer\Ui\Component\Form\AddressFieldset; +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +/** + * Test for class \Magento\Customer\Ui\Component\Form\AddressFieldset + */ +class AddressFieldsetTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var AddressFieldset + */ + protected $fieldset; + + /** + * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $context; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->context = $this->getMockForAbstractClass( + \Magento\Framework\View\Element\UiComponent\ContextInterface::class + ); + $this->fieldset = new AddressFieldset( + $this->context, + [], + [] + ); + } + + /** + * Run test for canShow() method + * + * @return void + * + */ + public function testCanShow() + { + $this->context->expects($this->atLeastOnce())->method('getRequestParam')->with('id') + ->willReturn(1); + $this->assertEquals(true, $this->fieldset->canShow()); + } + + /** + * Run test for canShow() method without customer id in context + * + * @return void + * + */ + public function testCanShowWithoutId() + { + $this->context->expects($this->atLeastOnce())->method('getRequestParam')->with('id') + ->willReturn(null); + $this->assertEquals(false, $this->fieldset->canShow()); + } +} diff --git a/app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php b/app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php new file mode 100644 index 0000000000000..4d7464b321e85 --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Ui\Component\Form; + +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +/** + * Customer addresses fieldset class + */ +class AddressFieldset extends \Magento\Ui\Component\Form\Fieldset +{ + /** + * @param ContextInterface $context + * @param array $components + * @param array $data + */ + public function __construct( + ContextInterface $context, + array $components = [], + array $data = [] + ) { + $this->context = $context; + + parent::__construct($context, $components, $data); + } + + /** + * Can show customer addresses tab in tabs or not + * + * Will return false for not registered customer in a case when admin user created new customer account. + * Needed to hide addresses tab from create new customer page + * + * @return boolean + */ + public function canShow(): bool + { + $customerId = $this->context->getRequestParam('id'); + return (bool)$customerId; + } +} diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php new file mode 100644 index 0000000000000..75c02974ded8f --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -0,0 +1,134 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Ui\Component\Listing\Address\Column; + +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Ui\Component\Listing\Columns\Column; +use Magento\Framework\UrlInterface; + +/** + * Prepare actions column for customer addresses grid + */ +class Actions extends Column +{ + const CUSTOMER_ADDRESS_PATH_DELETE = 'customer/address/delete'; + const CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING = 'customer/address/defaultShippingAddress'; + const CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING = 'customer/address/defaultBillingAddress'; + + /** + * @var UrlInterface + */ + protected $urlBuilder; + + /** + * @param ContextInterface $context + * @param UiComponentFactory $uiComponentFactory + * @param UrlInterface $urlBuilder + * @param array $components + * @param array $data + */ + public function __construct( + ContextInterface $context, + UiComponentFactory $uiComponentFactory, + UrlInterface $urlBuilder, + array $components = [], + array $data = [] + ) { + $this->urlBuilder = $urlBuilder; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + */ + public function prepareDataSource(array $dataSource): array + { + if (isset($dataSource['data']['items'])) { + foreach ($dataSource['data']['items'] as &$item) { + $name = $this->getData('name'); + if (isset($item['entity_id'])) { + $item[$name]['edit'] = [ + 'callback' => [ + [ + 'provider' => 'customer_form.areas.address.address' + . '.customer_address_update_modal.update_customer_address_form_loader', + 'target' => 'destroyInserted', + ], + [ + 'provider' => 'customer_form.areas.address.address' + . '.customer_address_update_modal', + 'target' => 'openModal', + ], + [ + 'provider' => 'customer_form.areas.address.address' + . '.customer_address_update_modal.update_customer_address_form_loader', + 'target' => 'render', + 'params' => [ + 'entity_id' => $item['entity_id'], + ], + ] + ], + 'href' => '#', + 'label' => __('Edit'), + 'hidden' => false, + ]; + + $item[$name]['set_default_shipping'] = [ + 'href' => $this->urlBuilder->getUrl( + self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, + ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] + ), + 'label' => __('Set as default shipping'), + 'confirm' => [ + 'title' => __('Set address as default shipping'), + 'message' => __( + 'Are you sure you want to set the address with ID: %1 as default shipping address?', + $item['entity_id'] + ) + ] + ]; + + $item[$name]['set_default_billing'] = [ + 'href' => $this->urlBuilder->getUrl( + self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, + ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] + ), + 'label' => __('Set as default billing'), + 'confirm' => [ + 'title' => __('Set address as default billing'), + 'message' => __( + 'Are you sure you want to set the address with ID: %1 as default billing address?', + $item['entity_id'] + ) + ] + ]; + + $item[$name]['delete'] = [ + 'href' => $this->urlBuilder->getUrl( + self::CUSTOMER_ADDRESS_PATH_DELETE, + ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] + ), + 'label' => __('Delete'), + 'confirm' => [ + 'title' => __('Delete address'), + 'message' => __( + 'Are you sure you want to delete the address with ID: %1?', + $item['entity_id'] + ) + ] + ]; + } + } + } + + return $dataSource; + } +} diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php new file mode 100644 index 0000000000000..438a16ec3ba55 --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php @@ -0,0 +1,37 @@ +<?php + +namespace Magento\Customer\Ui\Component\Listing\Address\Column; + +use Magento\Framework\Data\OptionSourceInterface; + +/** + * Class for process countries in customer addresses grid + */ +class Countries implements OptionSourceInterface +{ + /** + * @var \Magento\Directory\Model\ResourceModel\Country\CollectionFactory + */ + private $countryCollectionFactory; + + /** + * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $collectionFactory + */ + public function __construct( + \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $collectionFactory + ) { + $this->countryCollectionFactory = $collectionFactory; + } + + /** + * Get list of countries with country id as value and code as label + * + * @return array + */ + public function toOptionArray(): array + { + /** @var \Magento\Directory\Model\ResourceModel\Country\Collection $countryCollection */ + $countryCollection = $this->countryCollectionFactory->create(); + return $countryCollection->toOptionArray(); + } +} diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index 7971627521740..7e0b911e26184 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -120,6 +120,15 @@ <index referenceId="CUSTOMER_ADDRESS_ENTITY_PARENT_ID" indexType="btree"> <column name="parent_id"/> </index> + <index name="CUSTOMER_ADDRESS_ENTITY_FULLTEXT_INDEX" indexType="fulltext"> + <column name="firstname"/> + <column name="lastname"/> + <column name="street"/> + <column name="city"/> + <column name="region"/> + <column name="postcode"/> + <column name="telephone"/> + </index> </table> <table name="customer_address_entity_datetime" resource="default" engine="innodb" comment="Customer Address Entity Datetime"> diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 6e8c3dc68ed28..a63bff59f1dcf 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -223,6 +223,7 @@ <item name="customer_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Grid\Collection</item> <item name="customer_online_grid_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Online\Grid\Collection</item> <item name="customer_group_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Group\Grid\Collection</item> + <item name="customer_address_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Address\Grid\Collection</item> </argument> </arguments> </type> @@ -449,6 +450,14 @@ <argument name="resourceModel" xsi:type="string">Magento\Customer\Model\ResourceModel\Group</argument> </arguments> </type> + <type name="Magento\Customer\Model\ResourceModel\Address\Grid\Collection"> + <arguments> + <argument name="mainTable" xsi:type="string">customer_address_entity</argument> + <argument name="eventPrefix" xsi:type="string">customer_address_entity_grid_collection</argument> + <argument name="eventObject" xsi:type="string">customer_address_entity_grid_collection</argument> + <argument name="resourceModel" xsi:type="string">Magento\Customer\Model\ResourceModel\Address</argument> + </arguments> + </type> <preference for="Magento\Customer\Api\AccountDelegationInterface" type="Magento\Customer\Model\Delegation\AccountDelegation" /> diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml new file mode 100644 index 0000000000000..3acae3acec8aa --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <update handle="styles"/> + <body> + <referenceContainer name="content"> + <uiComponent name="customer_address_form"/> + </referenceContainer> + </body> +</page> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml new file mode 100644 index 0000000000000..a628c1b1b0b1e --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> + </item> + <item name="label" xsi:type="string" translate="true">Update Address</item> + <item name="reverseMetadataMerge" xsi:type="boolean">true</item> + <item name="template" xsi:type="string">templates/form/collapsible</item> + </argument> + <settings> + <buttons> + <button name="cancel" class="Magento\Customer\Block\Adminhtml\Edit\Address\CancelButton"/> + <button name="delete" class="Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton"/> + <button name="save" class="Magento\Customer\Block\Adminhtml\Edit\Address\SaveButton"/> + </buttons> + <namespace>customer_address_form</namespace> + <dataScope>data</dataScope> + <deps> + <dep>customer_address_form.customer_address_form_data_source</dep> + </deps> + </settings> + <dataSource name="customer_address_form_data_source"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Ui/js/form/provider</item> + </item> + </argument> + <settings> + <submitUrl path="customer/address/save"/> + <validateUrl path="customer/address/validate"/> + </settings> + <aclResource>Magento_Customer::manage</aclResource> + <dataProvider class="Magento\Customer\Model\Address\DataProvider" name="customer_address_form_data_source"> + <settings> + <requestFieldName>entity_id</requestFieldName> + <primaryFieldName>entity_id</primaryFieldName> + </settings> + </dataProvider> + </dataSource> + <fieldset name="general"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="is_collection" xsi:type="boolean">true</item> + </item> + </argument> + <settings> + <label/> + <dataScope/> + </settings> + + <field name="entity_id" formElement="hidden"> + <settings> + <dataType>text</dataType> + </settings> + </field> + <field name="default_shipping" sortOrder="0" formElement="checkbox"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="default" xsi:type="number">0</item> + </item> + </argument> + <settings> + <dataType>boolean</dataType> + <label translate="true">Default Shipping Address</label> + <dataScope>default_shipping</dataScope> + </settings> + <formElements> + <checkbox> + <settings> + <valueMap> + <map name="false" xsi:type="number">0</map> + <map name="true" xsi:type="number">1</map> + </valueMap> + <prefer>toggle</prefer> + </settings> + </checkbox> + </formElements> + </field> + <field name="default_billing" sortOrder="1" formElement="checkbox"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="default" xsi:type="number">0</item> + </item> + </argument> + <settings> + <dataType>boolean</dataType> + <label translate="true">Default Billing Address</label> + <dataScope>default_billing</dataScope> + </settings> + <formElements> + <checkbox> + <settings> + <valueMap> + <map name="false" xsi:type="number">0</map> + <map name="true" xsi:type="number">1</map> + </valueMap> + <prefer>toggle</prefer> + </settings> + </checkbox> + </formElements> + </field> + <field name="prefix" sortOrder="10" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Name Prefix</label> + </settings> + </field> + <field name="firstname" sortOrder="20" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">First Name</label> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="lastname" sortOrder="30" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Last Name</label> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="suffix" sortOrder="40" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Name Suffix</label> + </settings> + </field> + <field name="middlename" sortOrder="50" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Middle Name/Initial</label> + </settings> + </field> + <field name="company" sortOrder="60" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Company</label> + </settings> + </field> + <field name="city" sortOrder="80" formElement="input"> + <settings> + <dataType>text</dataType> + <label translate="true">City</label> + <visible>true</visible> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="country_id" component="Magento_Ui/js/form/element/country" sortOrder="90" formElement="select"> + <settings> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + <dataType>text</dataType> + </settings> + <formElements> + <select> + <settings> + <options class="Magento\Directory\Model\ResourceModel\Country\Collection"/> + </settings> + </select> + </formElements> + </field> + <field name="region_id" component="Magento_Ui/js/form/element/region" formElement="select"> + <settings> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + <dataType>text</dataType> + <label translate="true">State/Province</label> + </settings> + <formElements> + <select> + <settings> + <filterBy> + <field>country_id</field> + <target>${ $.provider }:${ $.parentScope }.country_id</target> + </filterBy> + <customEntry>region</customEntry> + <options class="Magento\Directory\Model\ResourceModel\Region\Collection"/> + </settings> + </select> + </formElements> + </field> + <field name="postcode" sortOrder="120" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Zip/Postal Code</label> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="telephone" sortOrder="130" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Phone Number</label> + </settings> + </field> + <field name="vat_id" sortOrder="140" formElement="input"> + <settings> + <dataType>text</dataType> + <label translate="true">VAT Number</label> + <validation> + <rule name="validate-number" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + </fieldset> +</form> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml new file mode 100644 index 0000000000000..cfc62fc99b10e --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing_data_source</item> + </item> + </argument> + <settings> + <spinner>customer_address_columns</spinner> + <deps> + <dep>customer_address_listing.customer_address_listing_data_source</dep> + </deps> + </settings> + <dataSource name="customer_address_listing_data_source" component="Magento_Ui/js/grid/provider"> + <settings> + <filterUrlParams> + <param name="id">*</param> + </filterUrlParams> + <storageConfig> + <param name="indexField" xsi:type="string">entity_id</param> + </storageConfig> + <updateUrl path="mui/index/render"/> + </settings> + <aclResource>Magento_Customer::manage</aclResource> + <dataProvider class="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider" name="customer_address_listing_data_source"> + <settings> + <requestFieldName>id</requestFieldName> + <primaryFieldName>entity_id</primaryFieldName> + </settings> + </dataProvider> + </dataSource> + <listingToolbar name="listing_top"> + <bookmark name="bookmarks"/> + <columnsControls name="columns_controls"/> + <!-- Filter Search --> + <filterSearch name="fulltext"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing_data_source</item> + <item name="chipsProvider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters_chips</item> + <item name="storageConfig" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> + <item name="namespace" xsi:type="string">current.search</item> + </item> + </item> + </argument> + </filterSearch> + <filters name="listing_filters"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="storageConfig" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> + <item name="namespace" xsi:type="string">current.filters</item> + </item> + <item name="childDefaults" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</item> + <item name="imports" xsi:type="array"> + <item name="visible" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item> + </item> + </item> + </item> + </argument> + </filters> + <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> + <action name="delete"> + <settings> + <confirm> + <message translate="true">Are you sure to delete selected address?</message> + <title translate="true">Delete items + + + delete + + + + + + + + + + + + false + + entity_id + true + customer_address_listing.customer_address_listing.address_columns.ids + + + + customer_address_listing.customer_address_listing.address_columns_editor + startEdit + + ${ $.$data.rowIndex } + true + + + + + + + entity_id + + + + + text + + + + + + text + + + + + + text + + + + + + text + + + + + + text + + + + + + text + + + + + + select + + select + + + + + + text + + text + + + + + + + entity_id + + + + diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js new file mode 100644 index 0000000000000..a715aae1ebd96 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js @@ -0,0 +1,17 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'uiElement' +], function($, Component) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_Customer/default-address' + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js new file mode 100644 index 0000000000000..3a1500e5dc99e --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -0,0 +1,44 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/button' +], function (Button) { + 'use strict'; + + return Button.extend({ + initialize: function () { + this._super(); + if (!this.parent_id) { + this.visible(this.entity_id); + } + }, + + defaults: { + entity_id: null, + parent_id: null + }, + + /** + * Apply action on target component, + * but previously create this component from template if it is not existed + * + * @param {Object} action - action configuration + */ + applyAction: function (action) { + if (action.params && action.params[0]) { + action.params[0].entity_id = this.entity_id; + action.params[0].parent_id = this.parent_id; + } else { + action.params = [{ + entity_id: this.entity_id, + parent_id: this.parent_id + }]; + } + + this._super(); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js new file mode 100644 index 0000000000000..94701f4c1af99 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js @@ -0,0 +1,203 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'Magento_Ui/js/modal/modal-component', + 'uiRegistry', + 'underscore' +], function ($, Modal, registry, _) { + 'use strict'; + + return Modal.extend({ + defaults: { + modules: { + emailProvider: '${ $.emailProvider }' + } + }, + + /** + * Initializes component. + * + * @returns {Object} Chainable. + */ + initialize: function () { + this._super(); + + // console.log(this.name); + + return this; + }, + + /** + * Open modal. + */ + openModal: function (data) { + debugger; + if (data == null){ + // add + this.setTitle(this.options.title); + this._super(); + } else { + // edit + var addressId = data.uuid; + var address = { + 'city': 'city', + 'company': 'company', + 'country_id': 'country_id', + 'customer_id': 'customer_id', + 'created_at': 'created_at', + 'default_billing': 'default_billing', + 'default_shipping': 'default_shipping', + 'entity_id': 'entity_id', + 'fax': 'fax', + 'firstname': 'firstname', + 'increment_id': 'increment_id', + 'is_active': 'is_active', + 'lastname': 'lastname', + 'middlename': 'middlename', + 'parent_id': 'parent_id', + 'postcode': 'postcode', + 'prefix': 'prefix', + 'region': 'region', + 'region_id': 'region_id', + 'street': [0, 1], + 'suffix': 'suffix', + 'telephone': 'telephone', + 'updated_at': 'updated_at', + 'vat_id': 'vat_id', + 'vat_is_valid': 'vat_is_valid', + 'vat_request_date': 'vat_request_date', + 'vat_request_id': 'vat_request_id', + 'vat_request_success': 'vat_request_success' + }; + + var source = registry.get('customer_form.customer_form_data_source'); + var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; + + _.each(address, function(value, key) { + if (key === 'default_billing' || key === 'default_shipping') { + var defaultValue = source.get('data.address.' + addressId + '.' + value); + // convert boolean to integer + var val = +defaultValue; + source.set(modal + '.' + key, val.toString()); + } else if (key === 'street' && _.isArray(address[key])) { + _.each(address[key], function(element, index) { + source.set(modal + '.' + key + '[' + index + ']', source.get('data.address.' + addressId + '.' + key + '.' + element)); + }); + } else { + source.set(modal + '.' + key, source.get('data.address.' + addressId + '.' + value)); + } + }); + + this.setTitle(this.options.title); + this._super(); + } + }, + + /** + * Close popup modal. + * @public + */ + closeModal: function () { + debugger; + this._clearData(); + this._super(); + }, + + /** + * Clear modal data. + * + * @private + */ + _clearData: function () { + debugger; + var address = { + 'city': '', + 'company': '', + 'country_id': '', + 'default_billing': "0", + 'default_shipping': "0", + 'entity_id': '', + 'firstname': '', + 'is_active': '', + 'lastname': '', + 'middlename': '', + 'postcode': '', + 'prefix': '', + 'region': '', + 'region_id': '', + 'street[0]': '', + 'street[1]': '', + 'suffix': '', + 'telephone': '', + 'vat_id': '' + }; + + var source = registry.get('customer_form.customer_form_data_source'); + var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; + + _.each(address, function(value, key) { + source.set(modal + '.' + key, value); + }); + }, + + /** + * Open modal. + */ + save: function () { + debugger; + + var address = { + 'city': 'city', + 'company': 'company', + 'country_id': 'country_id', + 'customer_id': 'customer_id', + 'created_at': 'created_at', + 'default_billing': 'default_billing', + 'default_shipping': 'default_shipping', + 'entity_id': 'entity_id', + 'fax': 'fax', + 'firstname': 'firstname', + 'increment_id': 'increment_id', + 'is_active': 'is_active', + 'lastname': 'lastname', + 'middlename': 'middlename', + 'parent_id': 'parent_id', + 'postcode': 'postcode', + 'prefix': 'prefix', + 'region': 'region', + 'region_id': 'region_id', + 'street': ['street[0]', 'street[1]'], + 'suffix': 'region_id', + 'telephone': 'telephone', + 'updated_at': 'updated_at', + 'vat_id': 'vat_id', + 'vat_is_valid': 'vat_is_valid', + 'vat_request_date': 'vat_request_date', + 'vat_request_id': 'vat_request_id', + 'vat_request_success': 'vat_request_success' + }; + + var source = registry.get('customer_form.customer_form_data_source'); + var formData = source.get('data.address_listing.address_form.update_customer_address_form_modal'); + var entityId = formData.entity_id; + + $.ajax({ + url: this.options.url, + showLoader: true, + data: formData, + type: "POST", + dataType: 'json', + success: function(data) { + console.log('SUCCESS: ', data); + }, + error: function(data) { + console.log('ERROR: ', data); + } + }); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js new file mode 100644 index 0000000000000..edfb004654a9b --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -0,0 +1,164 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/insert-form' +], function (Insert) { + 'use strict'; + + return Insert.extend({ + // Should be refactored after form save.!!!!! + // defaults: { + // updateModalProvider: '${ $.parentName }', + // subTitlePrefix: $t('Belongs to '), + // switcherSelector: '.store-switcher', + // toRemove: [], + // // imports: { + // // removeResponseData: '${ $.removeResponseProvider }', + // // modalTitle: '${ $.modalTitleProvider }', + // // modalSubTitle: '${ $.modalSubTitleProvider }', + // // destroyClosedModalContents: '${ $.updateModalProvider }:state' + // // }, + // // listens: { + // // responseData: 'afterUpdate', + // // removeResponseData: 'afterRemove', + // // modalTitle: 'changeModalTitle', + // // modalSubTitle: 'changeModalSubTitle' + // // }, + // modules: { + // updateModal: '${ $.updateModalProvider }', + // removeModal: '${ $.removeModalProvider }', + // upcomingListing: 'index = ${ $.upcomingListingProvider }' + // } + // }, + // + // /** @inheritdoc **/ + // initialize: function () { + // _.bindAll(this, 'onSwitcherSelect'); + // this._super(); + // this.updateModal(this.initSwitcherHandler.bind(this)); + // + // return this; + // }, + // + // initConfig: function (options) { + // debugger; + // return this._super(); + // }, + // + // /** @inheritdoc */ + // destroyInserted: function () { + // if (this.isRendered) { + // _.each(this.toRemove, function (componentName) { + // registry.get(componentName, function (component) { + // if (component.hasOwnProperty('delegate')) { + // component.delegate('destroy'); + // } else { + // component.destroy(); + // } + // }); + // }); + // } + // + // this._super(); + // }, + // + // // /** + // // * Form save callback. + // // * + // // * @param {Object} data + // // */ + // // afterUpdate: function (data) { + // // if (!data.error) { + // // this.updateModal('closeModal'); + // // this.upcomingListing('reload'); + // // } + // // }, + // + // // /** + // // * Form remove callback. + // // * + // // * @param {Object} data + // // */ + // // afterRemove: function (data) { + // // if (!data.error) { + // // this.removeModal('closeModal'); + // // this.afterUpdate(data); + // // } + // // }, + // + // // /** + // // * Change modal title. + // // * + // // * @param {String} title + // // */ + // // changeModalTitle: function (title) { + // // this.updateModal('setTitle', title); + // // }, + // // + // // /** + // // * Change modal sub title. + // // * + // // * @param {String} subTitle + // // */ + // // changeModalSubTitle: function (subTitle) { + // // subTitle = subTitle ? + // // this.subTitlePrefix + this.modalTitle + ' ' + subTitle : + // // ''; + // // + // // this.updateModal('setSubTitle', subTitle); + // // }, + // + // /** + // * Destroy contents of modal when it is closed + // * + // * @param {Boolean} state + // */ + // destroyClosedModalContents: function (state) { + // if (state === false) { + // this.destroyInserted(); + // } + // }, + // + // /** + // * Switcher initialization. + // */ + // initSwitcherHandler: function () { + // var switcherSelector = this.updateModal().rootSelector + ' ' + this.switcherSelector, + // self = this; + // + // $.async(switcherSelector, function (switcher) { + // $(switcher).on('click', 'li a', self.onSwitcherSelect); + // }); + // }, + // + // /** + // * Store switcher selection handler. + // * @param {Object} e - event object. + // */ + // onSwitcherSelect: function (e) { + // var self = this, + // param = $(e.currentTarget).data('param'), + // params = { + // store: 0 + // }; + // + // params[param] = $(e.currentTarget).data('value'); + // + // uiConfirm({ + // content: $t('Please confirm scope switching. All data that hasn\'t been saved will be lost.'), + // actions: { + // + // /** Confirm callback. */ + // confirm: function () { + // self.destroyInserted(); + // params = _.extend(self.previousParams, params); + // self.render(params); + // } + // } + // }); + // } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html new file mode 100644 index 0000000000000..1ee5a4da81d2b --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -0,0 +1,42 @@ +
    +
    +
    +
    + +
    +
    + + + + + +
    + + +
    +
    + + +
    +
    + + + + +
    +
    + + +
    T: +
    + +
    F: +
    + +
    VAT: +
    +
    + +
    +
    +
    diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index d2a9b3f44624d..1eb3652628c28 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -43,7 +43,7 @@ - + id entity_id @@ -303,262 +303,175 @@ -
    - - - true - Are you sure you want to delete this item? - - +
    + false + fieldset + + true + - - - - address - - - - number - false - - - + - address + billing-address + Default Billing Address + customer-default-billing-address-content + The customer does not have default billing address - text - true - - - - - - address - - - - - true - - text - ${ $.provider }:data.customer.firstname + ${ $.provider}:data.default_billing_address - - - - - address - - - - text - true - - - - - - address + + + + + - address + shipping-address + Default Shipping Address + customer-default-shipping-address-content + The customer does not have default shipping address - - true - - text - - - - - - address - - - - - true - - text - ${ $.provider }:data.customer.website_id + ${ $.provider}:data.default_shipping_address - - - - - address - - - - text - false - - - - - - address - - - - - true - - text - - - - - - - - - address - - - - - true - - text - - - - - - address - - - - text - - - - - - address - - - - - 0 - - text - - - - - - address + + + + + - ui/form/element/checkbox - boolean + + + - - - - Default Shipping Address - - - - + + + + + customer_address_edit + 1 + + false + ${ $.parentName } + ${ $.ns }.customer_address_form_data_source + customer_address_form + + + + + + + false + true + + customer_address_listing.customer_address_listing_data_source + customer_address_listing.customer_address_listing.customer_address_listing_columns.ids + true + customer_address_listing + customer_address_listing + + ${ $.externalProvider }:params.parent_id + + + ${ $.provider }:data.customer.entity_id + + +
    diff --git a/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php b/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php index c2460fd8385c1..f15a97e96c549 100644 --- a/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php +++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php @@ -35,6 +35,7 @@ public function prepare() $this->getData(), [ 'config' => [ + 'dataScope' => $this->getName(), 'uploaderConfig' => [ 'url' => $url ], diff --git a/app/code/Magento/Ui/Component/Form/Fieldset.php b/app/code/Magento/Ui/Component/Form/Fieldset.php index 745068ca0fa8a..ebfe58f3abb89 100644 --- a/app/code/Magento/Ui/Component/Form/Fieldset.php +++ b/app/code/Magento/Ui/Component/Form/Fieldset.php @@ -5,11 +5,7 @@ */ namespace Magento\Ui\Component\Form; -use Magento\Ui\Component\Container; use Magento\Ui\Component\AbstractComponent; -use Magento\Framework\View\Element\UiComponentFactory; -use Magento\Framework\View\Element\UiComponentInterface; -use Magento\Framework\View\Element\UiComponent\ContextInterface; /** * @api @@ -33,4 +29,14 @@ public function getComponentName() { return static::NAME; } + + /** + * Check that fieldset can be shown. + * + * @return bool + */ + public function canShow(): bool + { + return true; + } } diff --git a/app/code/Magento/Ui/Component/Layout/Tabs.php b/app/code/Magento/Ui/Component/Layout/Tabs.php index 8ceac716ae218..02e8979f525ef 100644 --- a/app/code/Magento/Ui/Component/Layout/Tabs.php +++ b/app/code/Magento/Ui/Component/Layout/Tabs.php @@ -11,6 +11,7 @@ use Magento\Framework\View\Element\UiComponent\LayoutInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Ui\Component\Form\Fieldset; use Magento\Ui\Component\Layout\Tabs\TabInterface; /** @@ -89,6 +90,9 @@ protected function addChildren(array &$topNode, UiComponentInterface $component, $this->addWrappedBlock($childComponent, $childrenAreas); continue; } + if ($childComponent instanceof Fieldset && false === $childComponent->canShow()) { + continue; + } $name = $childComponent->getName(); $config = $childComponent->getData('config'); diff --git a/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php new file mode 100644 index 0000000000000..9a8cf28ae0719 --- /dev/null +++ b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php @@ -0,0 +1,69 @@ +context = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContextInterface::class) + ->getMockForAbstractClass(); + + $this->fieldset = new Fieldset( + $this->context, + [], + [] + ); + } + + /** + * Run test for getComponentName() method + * + * @return void + * + */ + public function testGetComponentName() + { + $this->assertEquals(self::NAME, $this->fieldset->getComponentName()); + } + + /** + * Run test for canShow() method + * + * @return void + * + */ + public function testCanShow() + { + $this->assertEquals(true, $this->fieldset->canShow()); + } +} diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js index 2c12486ceb519..dbea61b13e626 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js @@ -5,6 +5,9 @@ /** * @api + * @deprecated as customer addresses are handled by ui components. + * This collection component manages rendering address list in Addresses tab of customer. + * Now address list is rendered with ui component listing. */ define([ 'underscore', @@ -46,6 +49,7 @@ define([ * @param {Object} elem - Incoming child. */ initElement: function (elem) { + debugger; this._super(); elem.activate(); @@ -153,6 +157,7 @@ define([ * Creates function that removes element * from collection using '_removeChild' method. * @param {Object} elem - Element that should be removed. + * @deprecated Not used anymore */ removeAddress: function (elem) { var self = this; @@ -169,7 +174,7 @@ define([ }, /** - * Removes elememt from both collection and data storage, + * Removes element from both collection and data storage, * activates first element if removed one was active, * triggers 'update' event. * diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js index c2a65371471c5..ae7f375bdca02 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js @@ -5,6 +5,9 @@ /** * @api + * @deprecated as customer addresses are handled by ui components. + * This item component renders address list item preview in Addresses tab. + * But now address list item is rendered with ui component in customer form. */ define([ 'underscore', @@ -19,7 +22,7 @@ define([ }; /** - * Parses incoming data and returnes result merged with default preview config + * Parses incoming data and returns result merged with default preview config * * @param {Object|String} data * @return {Object} diff --git a/app/code/Magento/Ui/view/base/web/templates/form/insert.html b/app/code/Magento/Ui/view/base/web/templates/form/insert.html index e19b2784e6bc6..e590b5e2adedf 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/insert.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/insert.html @@ -6,9 +6,6 @@ -->
    diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index a80cc9a5163f8..8a5fe698eb196 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -3,14 +3,72 @@ // * See COPYING.txt for license details. // */ -// General rule hides group legend and shows first field label instead -// in app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less -// This must be reset for Customer Address page -.address-item-edit-content { +.customer_form_areas_address_address_customer_address_update_modal_update_customer_address_form_loader { .admin__field { - legend { - &.admin__field-label { - opacity: 1; + .admin__field { + .admin__field-label { + background: none; + } + } + } +} + +.customer-address-form { + + *, *:before, *:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + + address { + font-style: normal; + } + + .customer-default-billing-address-content, + .customer-default-shipping-address-content + { + float: left; + width: 550px; + } + + .edit-default-billing-address-button, + .edit-default-shipping-address-button { + float: left; + position: relative; + top: 2px; + } + + .edit-default-billing-address-button { + left: -336px; + } + + .edit-default-shipping-address-button { + left: -315px; + } + + .customer_form_areas_address_address_customer_address_listing { + clear: both; + } + + .add-new-address-button { + position: relative; + clear: both; + float: right; + margin-bottom: 30px; + } + + .address-information { + float: left; + margin-bottom: 20px; + + address { + float: left; + + .address_caption { + font-size: 18px; + font-weight: bold; + margin-bottom: 16px; } } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php new file mode 100644 index 0000000000000..6a41dd70e89e2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -0,0 +1,222 @@ +customerRepository = Bootstrap::getObjectManager()->get( + \Magento\Customer\Api\CustomerRepositoryInterface::class + ); + $this->accountManagement = Bootstrap::getObjectManager()->get( + \Magento\Customer\Api\AccountManagementInterface::class + ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->customerAddress = $this->objectManager->get(\Magento\Customer\Controller\Adminhtml\Address\Save::class); + } + + /** + * @inheritDoc + */ + protected function tearDown() + { + /** + * Unset customer data + */ + Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->setCustomerData(null); + + /** + * Unset messages + */ + Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getMessages(true); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_no_address.php + * + * Check that customer id set and addresses saved + */ + public function testSaveActionWithValidAddressData() + { + $customer = $this->customerRepository->get('customer5@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => 'test firstname', + 'lastname' => 'test lastname', + 'street' => ['test street'], + 'city' => 'test city', + 'region_id' => 10, + 'country_id' => 'US', + 'postcode' => '01001', + 'telephone' => '+7000000001', + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); + + /** + * Check that customer data were cleaned after it was saved successfully + */ + $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); + + /** + * Check that success message is set + */ + $this->assertSessionMessages( + $this->logicalNot($this->isEmpty()), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + + $customer = $this->customerRepository->getById($customerId); + + $this->assertEquals('Firstname', $customer->getFirstname()); + $addresses = $customer->getAddresses(); + $this->assertCount(1, $addresses); + $this->assertNull($this->accountManagement->getDefaultBillingAddress($customerId)); + $this->assertNull($this->accountManagement->getDefaultShippingAddress($customerId)); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_no_address.php + * + * Check that customer id set and addresses saved + */ + public function testSaveActionWithDefaultShippingAndBilling() + { + $customer = $this->customerRepository->get('customer5@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => 'test firstname', + 'lastname' => 'test lastname', + 'street' => ['test street'], + 'city' => 'test city', + 'region_id' => 10, + 'country_id' => 'US', + 'postcode' => '01001', + 'telephone' => '+7000000001', + 'default_billing' => true, + 'default_shipping' => true + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); + + /** + * Check that customer data were cleaned after it was saved successfully + */ + $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); + + /** + * Check that success message is set + */ + $this->assertSessionMessages( + $this->logicalNot($this->isEmpty()), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + + /** + * Remove stored customer from registry + */ + $this->objectManager->get(\Magento\Customer\Model\CustomerRegistry::class)->remove($customerId); + $customer = $this->customerRepository->get('customer5@example.com'); + $this->assertEquals('Firstname', $customer->getFirstname()); + $addresses = $customer->getAddresses(); + $this->assertCount(1, $addresses); + + $this->assertNotNull($this->accountManagement->getDefaultBillingAddress($customerId)); + $this->assertNotNull($this->accountManagement->getDefaultShippingAddress($customerId)); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_sample.php + * + * Check that customer id set and addresses saved + */ + public function testSaveActionWithExistingAdresses() + { + $customer = $this->customerRepository->get('customer@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => 'test firstname', + 'lastname' => 'test lastname', + 'street' => ['test street'], + 'city' => 'test city', + 'region_id' => 10, + 'country_id' => 'US', + 'postcode' => '01001', + 'telephone' => '+7000000001', + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); + + /** + * Check that customer data were cleaned after it was saved successfully + */ + $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); + + /** + * Check that success message is set + */ + $this->assertSessionMessages( + $this->logicalNot($this->isEmpty()), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + + $customer = $this->customerRepository->getById($customerId); + + $this->assertEquals('test firstname', $customer->getFirstname()); + $addresses = $customer->getAddresses(); + $this->assertCount(4, $addresses); + } +} diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt index 877583e5b6a29..5c5c380c4dd33 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt @@ -1 +1 @@ -# Format: or simply +# Format: or simply \ No newline at end of file diff --git a/setup/performance-toolkit/config/customerConfig.xml b/setup/performance-toolkit/config/customerConfig.xml index 8fd74d7b53885..b77d9f6d4c941 100644 --- a/setup/performance-toolkit/config/customerConfig.xml +++ b/setup/performance-toolkit/config/customerConfig.xml @@ -6,5 +6,5 @@ */ --> - 2 + 5 From 3f5bcdd911b1d7b9604362f078bcfd9b7baa9d3f Mon Sep 17 00:00:00 2001 From: matt Date: Fri, 26 Oct 2018 15:01:27 +0200 Subject: [PATCH 0318/1158] magento2#222 Apply changes from CR for PR 162 --- .../Model/Customer/UpdateAccountInformation.php | 2 +- .../Model/Resolver/ChangePassword.php | 6 +++--- .../Model/Resolver/GenerateCustomerToken.php | 4 ++-- .../Model/Resolver/RevokeCustomerToken.php | 2 +- app/code/Magento/CustomerGraphQl/etc/schema.graphqls | 12 ++++++++---- .../Exception/GraphQlAlreadyExistsException.php | 2 +- .../Exception/GraphQlAuthenticationException.php | 2 +- .../Exception/GraphQlAuthorizationException.php | 2 +- .../Exception/GraphQlNoSuchEntityException.php | 2 +- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateAccountInformation.php b/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateAccountInformation.php index d235d51b5e52d..36365f1910f27 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateAccountInformation.php +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateAccountInformation.php @@ -73,7 +73,7 @@ public function execute(int $customerId, array $data): void if (isset($data['email']) && $customer->getEmail() !== $data['email']) { if (!isset($data['password']) || empty($data['password'])) { - throw new GraphQlInputException(__('For changing "email" you should provide current "password".')); + throw new GraphQlInputException(__('Provide the current "password" to change "email".')); } $this->checkCustomerPassword->execute($data['password'], $customerId); diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/ChangePassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/ChangePassword.php index 98b0975b37169..78fa852a7ac59 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/ChangePassword.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/ChangePassword.php @@ -17,7 +17,7 @@ use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; /** - * @inheritdoc + * Change customer password resolver */ class ChangePassword implements ResolverInterface { @@ -70,11 +70,11 @@ public function resolve( array $args = null ) { if (!isset($args['currentPassword'])) { - throw new GraphQlInputException(__('"currentPassword" value should be specified')); + throw new GraphQlInputException(__('Specify the "currentPassword" value.')); } if (!isset($args['newPassword'])) { - throw new GraphQlInputException(__('"newPassword" value should be specified')); + throw new GraphQlInputException(__('Specify the "newPassword" value.')); } $currentUserId = $context->getUserId(); diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/GenerateCustomerToken.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/GenerateCustomerToken.php index 9719d048f606b..1bd77fe1cde8f 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/GenerateCustomerToken.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/GenerateCustomerToken.php @@ -45,11 +45,11 @@ public function resolve( array $args = null ) { if (!isset($args['email'])) { - throw new GraphQlInputException(__('"email" value should be specified')); + throw new GraphQlInputException(__('Specify the "email" value.')); } if (!isset($args['password'])) { - throw new GraphQlInputException(__('"password" value should be specified')); + throw new GraphQlInputException(__('Specify the "password" value.')); } try { diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/RevokeCustomerToken.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/RevokeCustomerToken.php index d3b16c05a6492..3301162dc0088 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/RevokeCustomerToken.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/RevokeCustomerToken.php @@ -55,6 +55,6 @@ public function resolve( $this->checkCustomerAccount->execute($currentUserId, $currentUserType); - return $this->customerTokenService->revokeCustomerAccessToken((int)$currentUserId); + return ['result' => $this->customerTokenService->revokeCustomerAccessToken((int)$currentUserId)]; } } diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index b8411f00c5cb1..ca4ac6cc245a7 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -6,10 +6,10 @@ type Query { } type Mutation { - generateCustomerToken(email: String!, password: String!): CustomerToken @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\GenerateCustomerToken") @doc(description:"Retrieve Customer token") - changeCustomerPassword(currentPassword: String!, newPassword: String!): Customer @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ChangePassword") @doc(description:"Changes password for logged in customer") - updateCustomer (input: UpdateCustomerInput): UpdateCustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Update customer personal information") - revokeCustomerToken: Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RevokeCustomerToken") @doc(description:"Revoke Customer token") + generateCustomerToken(email: String!, password: String!): CustomerToken @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\GenerateCustomerToken") @doc(description:"Retrieve the customer token") + changeCustomerPassword(currentPassword: String!, newPassword: String!): Customer @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ChangePassword") @doc(description:"Changes the password for the logged-in customer") + updateCustomer (input: UpdateCustomerInput!): UpdateCustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Update the customer's personal information") + revokeCustomerToken: RevokeCustomerTokenOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RevokeCustomerToken") @doc(description:"Revoke the customer token") } type CustomerToken { @@ -28,6 +28,10 @@ type UpdateCustomerOutput { customer: Customer! } +type RevokeCustomerTokenOutput { + result: Boolean! +} + type Customer @doc(description: "Customer defines the customer name and address and other details") { created_at: String @doc(description: "Timestamp indicating when the account was created") group_id: Int @doc(description: "The group assigned to the user. Default values are 0 (Not logged in), 1 (General), 2 (Wholesale), and 3 (Retailer)") diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAlreadyExistsException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAlreadyExistsException.php index d25707b2ca347..8275219e9e554 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAlreadyExistsException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAlreadyExistsException.php @@ -12,7 +12,7 @@ use Magento\Framework\Phrase; /** - * Class GraphQlAlreadyExistsException + * Exception for GraphQL to be thrown when data already exists */ class GraphQlAlreadyExistsException extends AlreadyExistsException implements ClientAware { diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthenticationException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthenticationException.php index 4df74bbf332cd..44c3d07bd186f 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthenticationException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthenticationException.php @@ -12,7 +12,7 @@ use Magento\Framework\Phrase; /** - * Class GraphQlAuthenticationException + * Exception for GraphQL to be thrown when authentication fails */ class GraphQlAuthenticationException extends AuthenticationException implements ClientAware { diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php index 5b76e0ab9f5ae..f71652edc63b3 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php @@ -11,7 +11,7 @@ use Magento\Framework\Exception\AuthorizationException; /** - * Class GraphQlAuthorizationException + * Exception for GraphQL to be thrown when authorization fails */ class GraphQlAuthorizationException extends AuthorizationException implements \GraphQL\Error\ClientAware { diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php index 05c5925e8d1e5..4bd24d6cfd4a7 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php @@ -11,7 +11,7 @@ use Magento\Framework\Phrase; /** - * Class GraphQlNoSuchEntityException + * Exception for GraphQL to be thrown when entity does not exists */ class GraphQlNoSuchEntityException extends NoSuchEntityException implements \GraphQL\Error\ClientAware { From b3a1cc66df511975ceec0d76447cbfadab35d7f8 Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov Date: Fri, 26 Oct 2018 16:33:32 +0300 Subject: [PATCH 0319/1158] MAGETWO-70532: [GitHub] REST API Missing Product_Option values for Order Items in salesOrderManagementV1 and salesOrderItemRepositoryV1 #9326 - Extracted setting product options to separate class - Added product options setter for order items collection - Covered changed by API functional test --- app/code/Magento/Bundle/etc/di.xml | 7 + app/code/Magento/Catalog/etc/di.xml | 7 + .../Magento/ConfigurableProduct/etc/di.xml | 7 + app/code/Magento/Downloadable/etc/di.xml | 7 + app/code/Magento/Sales/Model/Order.php | 12 +- .../Sales/Model/Order/ItemRepository.php | 119 +----- .../Sales/Model/Order/ProductOption.php | 103 +++++ .../Unit/Model/Order/ItemRepositoryTest.php | 366 ------------------ .../Magento/Sales/Service/V1/OrderGetTest.php | 145 +++++-- .../Sales/_files/order_with_bundle.php | 5 +- .../Interception/PluginList/PluginList.php | 2 +- 11 files changed, 270 insertions(+), 510 deletions(-) create mode 100644 app/code/Magento/Sales/Model/Order/ProductOption.php delete mode 100644 app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index 733b089dccd4b..d0e956efee694 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -140,6 +140,13 @@ + + + + Magento\Bundle\Model\ProductOptionProcessor + + + diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index a802496d299b8..7d2c3699ee2c2 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -602,6 +602,13 @@ + + + + Magento\Catalog\Model\ProductOptionProcessor + + + diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 1dbb0969687d5..102ed1314f864 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -125,6 +125,13 @@ + + + + Magento\ConfigurableProduct\Model\ProductOptionProcessor + + + Magento\ConfigurableProduct\Pricing\Price\FinalPriceResolver diff --git a/app/code/Magento/Downloadable/etc/di.xml b/app/code/Magento/Downloadable/etc/di.xml index 932e48e880880..4e9b0b55afb0b 100644 --- a/app/code/Magento/Downloadable/etc/di.xml +++ b/app/code/Magento/Downloadable/etc/di.xml @@ -77,6 +77,13 @@ + + + + Magento\Downloadable\Model\ProductOptionProcessor + + + diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 345ff036a2be6..19fcb0d3743e3 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -13,6 +13,7 @@ use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderStatusHistoryInterface; use Magento\Sales\Model\Order\Payment; +use Magento\Sales\Model\Order\ProductOption; use Magento\Sales\Model\ResourceModel\Order\Address\Collection; use Magento\Sales\Model\ResourceModel\Order\Creditmemo\Collection as CreditmemoCollection; use Magento\Sales\Model\ResourceModel\Order\Invoice\Collection as InvoiceCollection; @@ -279,6 +280,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ private $localeResolver; + /** + * @var ProductOption + */ + private $productOption; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -308,6 +314,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data * @param ResolverInterface $localeResolver + * @param ProductOption|null $productOption * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -338,7 +345,8 @@ public function __construct( \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [], - ResolverInterface $localeResolver = null + ResolverInterface $localeResolver = null, + ProductOption $productOption = null ) { $this->_storeManager = $storeManager; $this->_orderConfig = $orderConfig; @@ -361,6 +369,7 @@ public function __construct( $this->salesOrderCollectionFactory = $salesOrderCollectionFactory; $this->priceCurrency = $priceCurrency; $this->localeResolver = $localeResolver ?: ObjectManager::getInstance()->get(ResolverInterface::class); + $this->productOption = $productOption ?: ObjectManager::getInstance()->get(ProductOption::class); parent::__construct( $context, @@ -1347,6 +1356,7 @@ public function getItemsCollection($filterByTypes = [], $nonChildrenOnly = false if ($this->getId()) { foreach ($collection as $item) { $item->setOrder($this); + $this->productOption->add($item); } } return $collection; diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index 7916eb9db2b80..e9764e7d38c5a 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -6,10 +6,8 @@ namespace Magento\Sales\Model\Order; -use Magento\Catalog\Api\Data\ProductOptionExtensionFactory; -use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; -use Magento\Catalog\Model\ProductOptionFactory; use Magento\Catalog\Model\ProductOptionProcessorInterface; +use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\DataObject; use Magento\Framework\DataObject\Factory as DataObjectFactory; @@ -18,6 +16,7 @@ use Magento\Sales\Api\Data\OrderItemInterface; use Magento\Sales\Api\Data\OrderItemSearchResultInterfaceFactory; use Magento\Sales\Api\OrderItemRepositoryInterface; +use Magento\Sales\Model\Order\ProductOption; use Magento\Sales\Model\ResourceModel\Metadata; /** @@ -41,16 +40,6 @@ class ItemRepository implements OrderItemRepositoryInterface */ protected $searchResultFactory; - /** - * @var ProductOptionFactory - */ - protected $productOptionFactory; - - /** - * @var ProductOptionExtensionFactory - */ - protected $extensionFactory; - /** * @var ProductOptionProcessorInterface[] */ @@ -62,40 +51,41 @@ class ItemRepository implements OrderItemRepositoryInterface protected $registry = []; /** - * @var \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface + * @var CollectionProcessorInterface */ private $collectionProcessor; /** - * ItemRepository constructor. + * @var ProductOption + */ + private $productOption; + + /** * @param DataObjectFactory $objectFactory * @param Metadata $metadata * @param OrderItemSearchResultInterfaceFactory $searchResultFactory - * @param ProductOptionFactory $productOptionFactory - * @param ProductOptionExtensionFactory $extensionFactory + * @param CollectionProcessorInterface $collectionProcessor + * @param ProductOption $productOption * @param array $processorPool - * @param CollectionProcessorInterface|null $collectionProcessor */ public function __construct( DataObjectFactory $objectFactory, Metadata $metadata, OrderItemSearchResultInterfaceFactory $searchResultFactory, - ProductOptionFactory $productOptionFactory, - ProductOptionExtensionFactory $extensionFactory, - array $processorPool = [], - CollectionProcessorInterface $collectionProcessor = null + CollectionProcessorInterface $collectionProcessor, + ProductOption $productOption, + array $processorPool = [] ) { $this->objectFactory = $objectFactory; $this->metadata = $metadata; $this->searchResultFactory = $searchResultFactory; - $this->productOptionFactory = $productOptionFactory; - $this->extensionFactory = $extensionFactory; + $this->collectionProcessor = $collectionProcessor; + $this->productOption = $productOption; $this->processorPool = $processorPool; - $this->collectionProcessor = $collectionProcessor ?: $this->getCollectionProcessor(); } /** - * load entity + * Loads entity. * * @param int $id * @return OrderItemInterface @@ -116,7 +106,7 @@ public function get($id) ); } - $this->addProductOption($orderItem); + $this->productOption->add($orderItem); $this->addParentItem($orderItem); $this->registry[$id] = $orderItem; } @@ -137,7 +127,7 @@ public function getList(SearchCriteriaInterface $searchCriteria) $this->collectionProcessor->process($searchCriteria, $searchResult); /** @var OrderItemInterface $orderItem */ foreach ($searchResult->getItems() as $orderItem) { - $this->addProductOption($orderItem); + $this->productOption->add($orderItem); } return $searchResult; @@ -186,37 +176,6 @@ public function save(OrderItemInterface $entity) return $this->registry[$entity->getEntityId()]; } - /** - * Add product option data - * - * @param OrderItemInterface $orderItem - * @return $this - */ - protected function addProductOption(OrderItemInterface $orderItem) - { - /** @var DataObject $request */ - $request = $orderItem->getBuyRequest(); - - $productType = $orderItem->getProductType(); - if (isset($this->processorPool[$productType]) - && !$orderItem->getParentItemId()) { - $data = $this->processorPool[$productType]->convertToProductOption($request); - if ($data) { - $this->setProductOption($orderItem, $data); - } - } - - if (isset($this->processorPool['custom_options']) - && !$orderItem->getParentItemId()) { - $data = $this->processorPool['custom_options']->convertToProductOption($request); - if ($data) { - $this->setProductOption($orderItem, $data); - } - } - - return $this; - } - /** * Set parent item. * @@ -231,32 +190,6 @@ private function addParentItem(OrderItemInterface $orderItem) } } - /** - * Set product options data - * - * @param OrderItemInterface $orderItem - * @param array $data - * @return $this - */ - protected function setProductOption(OrderItemInterface $orderItem, array $data) - { - $productOption = $orderItem->getProductOption(); - if (!$productOption) { - $productOption = $this->productOptionFactory->create(); - $orderItem->setProductOption($productOption); - } - - $extensionAttributes = $productOption->getExtensionAttributes(); - if (!$extensionAttributes) { - $extensionAttributes = $this->extensionFactory->create(); - $productOption->setExtensionAttributes($extensionAttributes); - } - - $extensionAttributes->setData(key($data), current($data)); - - return $this; - } - /** * Retrieve order item's buy request * @@ -288,20 +221,4 @@ protected function getBuyRequest(OrderItemInterface $entity) return $request; } - - /** - * Retrieve collection processor - * - * @deprecated 100.2.0 - * @return CollectionProcessorInterface - */ - private function getCollectionProcessor() - { - if (!$this->collectionProcessor) { - $this->collectionProcessor = \Magento\Framework\App\ObjectManager::getInstance()->get( - \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface::class - ); - } - return $this->collectionProcessor; - } } diff --git a/app/code/Magento/Sales/Model/Order/ProductOption.php b/app/code/Magento/Sales/Model/Order/ProductOption.php new file mode 100644 index 0000000000000..dc9ec42e27e60 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/ProductOption.php @@ -0,0 +1,103 @@ +productOptionFactory = $productOptionFactory; + $this->extensionFactory = $extensionFactory; + $this->processorPool = $processorPool; + } + + /** + * Adds product option to the order item. + * + * @param OrderItemInterface $orderItem + */ + public function add(OrderItemInterface $orderItem): void + { + /** @var DataObject $request */ + $request = $orderItem->getBuyRequest(); + + $productType = $orderItem->getProductType(); + if (isset($this->processorPool[$productType]) + && !$orderItem->getParentItemId()) { + $data = $this->processorPool[$productType]->convertToProductOption($request); + if ($data) { + $this->setProductOption($orderItem, $data); + } + } + + if (isset($this->processorPool['custom_options']) + && !$orderItem->getParentItemId()) { + $data = $this->processorPool['custom_options']->convertToProductOption($request); + if ($data) { + $this->setProductOption($orderItem, $data); + } + } + } + + /** + * Sets product options data. + * + * @param OrderItemInterface $orderItem + * @param array $data + */ + private function setProductOption(OrderItemInterface $orderItem, array $data): void + { + $productOption = $orderItem->getProductOption(); + if (!$productOption) { + $productOption = $this->productOptionFactory->create(); + $orderItem->setProductOption($productOption); + } + + $extensionAttributes = $productOption->getExtensionAttributes(); + if (!$extensionAttributes) { + $extensionAttributes = $this->extensionFactory->create(); + $productOption->setExtensionAttributes($extensionAttributes); + } + + $extensionAttributes->setData(key($data), current($data)); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php deleted file mode 100644 index 8be2c3c8612d7..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php +++ /dev/null @@ -1,366 +0,0 @@ -objectFactory = $this->getMockBuilder(\Magento\Framework\DataObject\Factory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->metadata = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Metadata::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->searchResultFactory = $this->getMockBuilder( - \Magento\Sales\Api\Data\OrderItemSearchResultInterfaceFactory::class - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->productOptionFactory = $this->getMockBuilder(\Magento\Catalog\Model\ProductOptionFactory::class) - ->setMethods([ - 'create', - ]) - ->disableOriginalConstructor() - ->getMock(); - - $this->collectionProcessor = $this->createMock( - \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface::class - ); - - $this->extensionFactory = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductOptionExtensionFactory::class) - ->setMethods([ - 'create', - ]) - ->disableOriginalConstructor() - ->getMock(); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage An ID is needed. Set the ID and try again. - */ - public function testGetWithNoId() - { - $model = new ItemRepository( - $this->objectFactory, - $this->metadata, - $this->searchResultFactory, - $this->productOptionFactory, - $this->extensionFactory, - [], - $this->collectionProcessor - ); - - $model->get(null); - } - - /** - * @expectedException \Magento\Framework\Exception\NoSuchEntityException - * @expectedExceptionMessage The entity that was requested doesn't exist. Verify the entity and try again. - */ - public function testGetEmptyEntity() - { - $orderItemId = 1; - - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) - ->method('getItemId') - ->willReturn(null); - - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); - - $model = new ItemRepository( - $this->objectFactory, - $this->metadata, - $this->searchResultFactory, - $this->productOptionFactory, - $this->extensionFactory, - [], - $this->collectionProcessor - ); - - $model->get($orderItemId); - } - - public function testGet() - { - $orderItemId = 1; - $productType = 'configurable'; - - $this->productOptionData = ['option1' => 'value1']; - - $this->getProductOptionExtensionMock(); - $productOption = $this->getProductOptionMock(); - $orderItemMock = $this->getOrderMock($productType, $productOption); - - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) - ->method('getItemId') - ->willReturn($orderItemId); - - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); - - $model = $this->getModel($orderItemMock, $productType); - $this->assertSame($orderItemMock, $model->get($orderItemId)); - - // Assert already registered - $this->assertSame($orderItemMock, $model->get($orderItemId)); - } - - public function testGetList() - { - $productType = 'configurable'; - $this->productOptionData = ['option1' => 'value1']; - $searchCriteriaMock = $this->getMockBuilder(\Magento\Framework\Api\SearchCriteria::class) - ->disableOriginalConstructor() - ->getMock(); - $this->getProductOptionExtensionMock(); - $productOption = $this->getProductOptionMock(); - $orderItemMock = $this->getOrderMock($productType, $productOption); - - $searchResultMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Item\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - $searchResultMock->expects($this->once()) - ->method('getItems') - ->willReturn([$orderItemMock]); - - $this->searchResultFactory->expects($this->once()) - ->method('create') - ->willReturn($searchResultMock); - - $model = $this->getModel($orderItemMock, $productType); - $this->assertSame($searchResultMock, $model->getList($searchCriteriaMock)); - } - - public function testDeleteById() - { - $orderItemId = 1; - $productType = 'configurable'; - - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) - ->method('getItemId') - ->willReturn($orderItemId); - $orderItemMock->expects($this->once()) - ->method('getProductType') - ->willReturn($productType); - $orderItemMock->expects($this->once()) - ->method('getBuyRequest') - ->willReturn($requestMock); - - $orderItemResourceMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemResourceMock->expects($this->once()) - ->method('delete') - ->with($orderItemMock) - ->willReturnSelf(); - - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); - $this->metadata->expects($this->exactly(1)) - ->method('getMapper') - ->willReturn($orderItemResourceMock); - - $model = $this->getModel($orderItemMock, $productType); - $this->assertTrue($model->deleteById($orderItemId)); - } - - /** - * @param \PHPUnit_Framework_MockObject_MockObject $orderItemMock - * @param string $productType - * @param array $data - * @return ItemRepository - */ - protected function getModel( - \PHPUnit_Framework_MockObject_MockObject $orderItemMock, - $productType, - array $data = [] - ) { - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - - $requestUpdateMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - $requestUpdateMock->expects($this->any()) - ->method('getData') - ->willReturn($data); - - $this->productOptionProcessorMock = $this->getMockBuilder( - \Magento\Catalog\Model\ProductOptionProcessorInterface::class - ) - ->getMockForAbstractClass(); - $this->productOptionProcessorMock->expects($this->any()) - ->method('convertToProductOption') - ->with($requestMock) - ->willReturn($this->productOptionData); - $this->productOptionProcessorMock->expects($this->any()) - ->method('convertToBuyRequest') - ->with($orderItemMock) - ->willReturn($requestUpdateMock); - - $model = new ItemRepository( - $this->objectFactory, - $this->metadata, - $this->searchResultFactory, - $this->productOptionFactory, - $this->extensionFactory, - [ - $productType => $this->productOptionProcessorMock, - 'custom_options' => $this->productOptionProcessorMock - ], - $this->collectionProcessor - ); - return $model; - } - - /** - * @param string $productType - * @param \PHPUnit_Framework_MockObject_MockObject $productOption - * @return \PHPUnit_Framework_MockObject_MockObject - */ - protected function getOrderMock($productType, $productOption) - { - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock->expects($this->once()) - ->method('getProductType') - ->willReturn($productType); - $orderItemMock->expects($this->once()) - ->method('getBuyRequest') - ->willReturn($requestMock); - $orderItemMock->expects($this->any()) - ->method('getProductOption') - ->willReturn(null); - $orderItemMock->expects($this->any()) - ->method('setProductOption') - ->with($productOption) - ->willReturnSelf(); - - return $orderItemMock; - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - protected function getProductOptionMock() - { - $productOption = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductOptionInterface::class) - ->getMockForAbstractClass(); - $productOption->expects($this->any()) - ->method('getExtensionAttributes') - ->willReturn(null); - - $this->productOptionFactory->expects($this->any()) - ->method('create') - ->willReturn($productOption); - - return $productOption; - } - - protected function getProductOptionExtensionMock() - { - $productOptionExtension = $this->getMockBuilder( - \Magento\Catalog\Api\Data\ProductOptionExtensionInterface::class - ) - ->setMethods([ - 'setData', - ]) - ->getMockForAbstractClass(); - $productOptionExtension->expects($this->any()) - ->method('setData') - ->with(key($this->productOptionData), current($this->productOptionData)) - ->willReturnSelf(); - - $this->extensionFactory->expects($this->any()) - ->method('create') - ->willReturn($productOptionExtension); - } -} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php index a10a224604897..09c49bed1de83 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php @@ -3,8 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Service\V1; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Webapi\Rest\Request; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Model\Order; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\WebapiAbstract; class OrderGetTest extends WebapiAbstract @@ -18,19 +25,24 @@ class OrderGetTest extends WebapiAbstract const ORDER_INCREMENT_ID = '100000001'; /** - * @var \Magento\Framework\ObjectManagerInterface + * @var ObjectManagerInterface */ - protected $objectManager; + private $objectManager; - protected function setUp() + /** + * @inheritdoc + */ + protected function setUp(): void { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = Bootstrap::getObjectManager(); } /** + * Checks order attributes. + * * @magentoApiDataFixture Magento/Sales/_files/order.php */ - public function testOrderGet() + public function testOrderGet(): void { $expectedOrderData = [ 'base_subtotal' => '100.0000', @@ -67,36 +79,21 @@ public function testOrderGet() 'region' => 'CA' ]; - /** @var \Magento\Sales\Model\Order $order */ - $order = $this->objectManager->create(\Magento\Sales\Model\Order::class); - $order->loadByIncrementId(self::ORDER_INCREMENT_ID); - - $serviceInfo = [ - 'rest' => [ - 'resourcePath' => self::RESOURCE_PATH . '/' . $order->getId(), - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, - ], - 'soap' => [ - 'service' => self::SERVICE_READ_NAME, - 'serviceVersion' => self::SERVICE_VERSION, - 'operation' => self::SERVICE_READ_NAME . 'get', - ], - ]; - $result = $this->_webApiCall($serviceInfo, ['id' => $order->getId()]); + $result = $this->makeServiceCall(self::ORDER_INCREMENT_ID); foreach ($expectedOrderData as $field => $value) { - $this->assertArrayHasKey($field, $result); - $this->assertEquals($value, $result[$field]); + self::assertArrayHasKey($field, $result); + self::assertEquals($value, $result[$field]); } - $this->assertArrayHasKey('payment', $result); + self::assertArrayHasKey('payment', $result); foreach ($expectedPayments as $field => $value) { - $this->assertEquals($value, $result['payment'][$field]); + self::assertEquals($value, $result['payment'][$field]); } - $this->assertArrayHasKey('billing_address', $result); + self::assertArrayHasKey('billing_address', $result); foreach ($expectedBillingAddressNotEmpty as $field) { - $this->assertArrayHasKey($field, $result['billing_address']); + self::assertArrayHasKey($field, $result['billing_address']); } self::assertArrayHasKey('extension_attributes', $result); @@ -112,28 +109,86 @@ public function testOrderGet() //check that nullable fields were marked as optional and were not sent foreach ($result as $value) { - $this->assertNotNull($value); + self::assertNotNull($value); } } /** + * Checks order extension attributes. + * * @magentoApiDataFixture Magento/Sales/_files/order_with_tax.php */ - public function testOrderGetExtensionAttributes() + public function testOrderGetExtensionAttributes(): void { $expectedTax = [ 'code' => 'US-NY-*-Rate 1', 'type' => 'shipping' ]; - /** @var \Magento\Sales\Model\Order $order */ - $order = $this->objectManager->create(\Magento\Sales\Model\Order::class); - $order->loadByIncrementId(self::ORDER_INCREMENT_ID); + $result = $this->makeServiceCall(self::ORDER_INCREMENT_ID); + $appliedTaxes = $result['extension_attributes']['applied_taxes']; + self::assertEquals($expectedTax['code'], $appliedTaxes[0]['code']); + $appliedTaxes = $result['extension_attributes']['item_applied_taxes']; + self::assertEquals($expectedTax['type'], $appliedTaxes[0]['type']); + self::assertNotEmpty($appliedTaxes[0]['applied_taxes']); + self::assertEquals(true, $result['extension_attributes']['converting_from_quote']); + } + + /** + * Checks if the order contains product option attributes. + * + * @magentoApiDataFixture Magento/Sales/_files/order_with_bundle.php + */ + public function testGetOrderWithProductOption(): void + { + $expected = [ + 'extension_attributes' => [ + 'bundle_options' => [ + [ + 'option_id' => 1, + 'option_selections' => [1], + 'option_qty' => 1 + ] + ] + ] + ]; + $result = $this->makeServiceCall(self::ORDER_INCREMENT_ID); + + $bundleProduct = $this->getBundleProduct($result['items']); + self::assertNotEmpty($bundleProduct, '"Bundle Product" should not be empty.'); + self::assertNotEmpty($bundleProduct['product_option'], '"Product Option" should not be empty.'); + self::assertEquals($expected, $bundleProduct['product_option']); + } + + /** + * Gets order by increment ID. + * + * @param string $incrementId + * @return OrderInterface + */ + private function getOrder(string $incrementId): OrderInterface + { + /** @var Order $order */ + $order = $this->objectManager->create(Order::class); + $order->loadByIncrementId($incrementId); + + return $order; + } + + /** + * Makes service call. + * + * @param string $incrementId + * @return array + */ + private function makeServiceCall(string $incrementId): array + { + $order = $this->getOrder($incrementId); $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH . '/' . $order->getId(), - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + 'httpMethod' => Request::HTTP_METHOD_GET, ], 'soap' => [ 'service' => self::SERVICE_READ_NAME, @@ -141,13 +196,23 @@ public function testOrderGetExtensionAttributes() 'operation' => self::SERVICE_READ_NAME . 'get', ], ]; - $result = $this->_webApiCall($serviceInfo, ['id' => $order->getId()]); + return $this->_webApiCall($serviceInfo, ['id' => $order->getId()]); + } - $appliedTaxes = $result['extension_attributes']['applied_taxes']; - $this->assertEquals($expectedTax['code'], $appliedTaxes[0]['code']); - $appliedTaxes = $result['extension_attributes']['item_applied_taxes']; - $this->assertEquals($expectedTax['type'], $appliedTaxes[0]['type']); - $this->assertNotEmpty($appliedTaxes[0]['applied_taxes']); - $this->assertEquals(true, $result['extension_attributes']['converting_from_quote']); + /** + * Gets a bundle product from the result. + * + * @param array $items + * @return array + */ + private function getBundleProduct(array $items): array + { + foreach ($items as $item) { + if ($item['product_type'] == 'bundle') { + return $item; + } + } + + return []; } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php index 6b6d6d6e6ec04..4473fb8dfe72c 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php @@ -6,7 +6,6 @@ declare(strict_types=1); use Magento\Sales\Api\Data\OrderItemInterface; -use Magento\Sales\Api\OrderItemRepositoryInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Item; @@ -29,6 +28,10 @@ OrderItemInterface::PRODUCT_TYPE => 'bundle', 'product_options' => [ 'product_calculations' => 0, + 'info_buyRequest' => [ + 'bundle_option' => [1 => 1], + 'bundle_option_qty' => 1, + ] ], 'children' => [ [ diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php index e21841b48bc13..a4f728454a524 100644 --- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php +++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php @@ -30,7 +30,7 @@ class PluginList extends Scoped implements InterceptionPluginList * * @var array */ - protected $_inherited; + protected $_inherited = []; /** * Inherited plugin data, preprocessed for read From e2b3f791b49e961f757685eaa06b3f221b718148 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 16:35:24 +0300 Subject: [PATCH 0320/1158] MAGETWO-95671: Remove address id from dialog alerts --- .../Component/Listing/Address/Column/Actions.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index 75c02974ded8f..e0fea85bd3d80 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -89,10 +89,7 @@ public function prepareDataSource(array $dataSource): array 'label' => __('Set as default shipping'), 'confirm' => [ 'title' => __('Set address as default shipping'), - 'message' => __( - 'Are you sure you want to set the address with ID: %1 as default shipping address?', - $item['entity_id'] - ) + 'message' => __('Are you sure you want to set the address as default shipping address?') ] ]; @@ -104,10 +101,7 @@ public function prepareDataSource(array $dataSource): array 'label' => __('Set as default billing'), 'confirm' => [ 'title' => __('Set address as default billing'), - 'message' => __( - 'Are you sure you want to set the address with ID: %1 as default billing address?', - $item['entity_id'] - ) + 'message' => __('Are you sure you want to set the address as default billing address?') ] ]; @@ -119,10 +113,7 @@ public function prepareDataSource(array $dataSource): array 'label' => __('Delete'), 'confirm' => [ 'title' => __('Delete address'), - 'message' => __( - 'Are you sure you want to delete the address with ID: %1?', - $item['entity_id'] - ) + 'message' => __('Are you sure you want to delete the address?') ] ]; } From f1a23e4418aeb12f0011af06dc40e2b3b1f17539 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 16:40:35 +0300 Subject: [PATCH 0321/1158] MAGETWO-95671: Remove address id from dialog alerts --- .../Listing/Address/Column/Actions.php | 20 +++++++++---------- .../ui_component/customer_address_form.xml | 12 +++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index e0fea85bd3d80..e44dc7988761f 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -81,27 +81,27 @@ public function prepareDataSource(array $dataSource): array 'hidden' => false, ]; - $item[$name]['set_default_shipping'] = [ + $item[$name]['set_default_billing'] = [ 'href' => $this->urlBuilder->getUrl( - self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, + self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), - 'label' => __('Set as default shipping'), + 'label' => __('Set as default billing'), 'confirm' => [ - 'title' => __('Set address as default shipping'), - 'message' => __('Are you sure you want to set the address as default shipping address?') + 'title' => __('Set address as default billing'), + 'message' => __('Are you sure you want to set the address as default billing address?') ] ]; - $item[$name]['set_default_billing'] = [ + $item[$name]['set_default_shipping'] = [ 'href' => $this->urlBuilder->getUrl( - self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, + self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), - 'label' => __('Set as default billing'), + 'label' => __('Set as default shipping'), 'confirm' => [ - 'title' => __('Set address as default billing'), - 'message' => __('Are you sure you want to set the address as default billing address?') + 'title' => __('Set address as default shipping'), + 'message' => __('Are you sure you want to set the address as default shipping address?') ] ]; diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index a628c1b1b0b1e..9e432f9f10e0c 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -60,7 +60,7 @@ text - + 0 @@ -68,8 +68,8 @@ boolean - - default_shipping + + default_billing @@ -83,7 +83,7 @@ - + 0 @@ -91,8 +91,8 @@ boolean - - default_billing + + default_shipping From 04af36ed9ec5bf498682b38857fd33991cfc13ff Mon Sep 17 00:00:00 2001 From: Jeroen Date: Fri, 26 Oct 2018 14:44:08 +0200 Subject: [PATCH 0322/1158] Cancel expired orders using OrderManagementInterface --- .../Model/CronJob/CleanExpiredOrders.php | 25 +++++++++++++++---- .../Model/CronJob/CleanExpiredOrdersTest.php | 22 +++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php index 8a7bd0260df0f..80370c21d4d7b 100644 --- a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php +++ b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php @@ -3,8 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Model\CronJob; +use Magento\Framework\App\ObjectManager; +use Magento\Sales\Api\OrderManagementInterface; +use Magento\Sales\Model\ResourceModel\Order\CollectionFactory; use Magento\Store\Model\StoresConfig; use Magento\Sales\Model\Order; @@ -16,20 +21,28 @@ class CleanExpiredOrders protected $storesConfig; /** - * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory + * @var CollectionFactory */ protected $orderCollectionFactory; + /** + * @var OrderManagementInterface + */ + private $orderManagement; + /** * @param StoresConfig $storesConfig - * @param \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $collectionFactory + * @param CollectionFactory $collectionFactory + * @param OrderManagementInterface|null $orderManagement */ public function __construct( StoresConfig $storesConfig, - \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $collectionFactory + CollectionFactory $collectionFactory, + OrderManagementInterface $orderManagement = null ) { $this->storesConfig = $storesConfig; $this->orderCollectionFactory = $collectionFactory; + $this->orderManagement = $orderManagement ?: ObjectManager::getInstance()->get(OrderManagementInterface::class); } /** @@ -48,8 +61,10 @@ public function execute() $orders->getSelect()->where( new \Zend_Db_Expr('TIME_TO_SEC(TIMEDIFF(CURRENT_TIMESTAMP, `updated_at`)) >= ' . $lifetime * 60) ); - $orders->walk('cancel'); - $orders->walk('save'); + + foreach ($orders->getAllIds() as $entityId) { + $this->orderManagement->cancel((int) $entityId); + } } } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php b/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php index 269ce829e64d3..6844b908ea98d 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php @@ -26,6 +26,11 @@ class CleanExpiredOrdersTest extends \PHPUnit\Framework\TestCase */ protected $orderCollectionMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $orderManagementMock; + /** * @var ObjectManager */ @@ -44,10 +49,12 @@ protected function setUp() ['create'] ); $this->orderCollectionMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Collection::class); + $this->orderManagementMock = $this->createMock(\Magento\Sales\Api\OrderManagementInterface::class); $this->model = new CleanExpiredOrders( $this->storesConfigMock, - $this->collectionFactoryMock + $this->collectionFactoryMock, + $this->orderManagementMock ); } @@ -64,8 +71,11 @@ public function testExecute() $this->collectionFactoryMock->expects($this->exactly(2)) ->method('create') ->willReturn($this->orderCollectionMock); + $this->orderCollectionMock->expects($this->exactly(2)) + ->method('getAllIds') + ->willReturn([1, 2]); $this->orderCollectionMock->expects($this->exactly(4))->method('addFieldToFilter'); - $this->orderCollectionMock->expects($this->exactly(4))->method('walk'); + $this->orderManagementMock->expects($this->exactly(4))->method('cancel'); $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); $selectMock->expects($this->exactly(2))->method('where')->willReturnSelf(); @@ -92,14 +102,18 @@ public function testExecuteWithException() $this->collectionFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->orderCollectionMock); + $this->orderCollectionMock->expects($this->once()) + ->method('getAllIds') + ->willReturn([1]); $this->orderCollectionMock->expects($this->exactly(2))->method('addFieldToFilter'); + $this->orderManagementMock->expects($this->once())->method('cancel'); $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); $selectMock->expects($this->once())->method('where')->willReturnSelf(); $this->orderCollectionMock->expects($this->once())->method('getSelect')->willReturn($selectMock); - $this->orderCollectionMock->expects($this->once()) - ->method('walk') + $this->orderManagementMock->expects($this->once()) + ->method('cancel') ->willThrowException(new \Exception($exceptionMessage)); $this->model->execute(); From dfc9cd0a5ce6d9285b56b40f9cc4c429f8d5f33c Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov Date: Fri, 26 Oct 2018 17:23:09 +0300 Subject: [PATCH 0323/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml index b10c8e5ad54a0..1cd0e15780c11 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductImagesTest.xml @@ -161,7 +161,7 @@ - + From 505ac52e2a242555873545faced2eef0a275fe4e Mon Sep 17 00:00:00 2001 From: Tobias Maile Date: Fri, 26 Oct 2018 16:55:02 +0200 Subject: [PATCH 0324/1158] GraphQL-202: [Mutations] adds sendEmailFriend Logic --- .../Model/Resolver/SendEmailToFriend.php | 147 ++++++++++++++++++ .../Magento/SendFriendGraphQl/etc/module.xml | 11 ++ .../SendFriendGraphQl/etc/schema.graphqls | 33 ++++ .../SendFriendGraphQl/registration.php | 9 ++ 4 files changed, 200 insertions(+) create mode 100644 app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php create mode 100644 app/code/Magento/SendFriendGraphQl/etc/module.xml create mode 100644 app/code/Magento/SendFriendGraphQl/etc/schema.graphqls create mode 100644 app/code/Magento/SendFriendGraphQl/registration.php diff --git a/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php b/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php new file mode 100644 index 0000000000000..56f6d20b20f18 --- /dev/null +++ b/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php @@ -0,0 +1,147 @@ +sendFriend = $sendFriend; + $this->productRepository = $productRepository; + $this->dataObjectFactory = $dataObjectFactory; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if ($this->sendFriend->getMaxSendsToFriend() && $this->sendFriend->isExceedLimit()) { + throw new GraphQlInputException(__('You can\'t send messages more than %1 times an hour.', + $this->sendFriend->getMaxSendsToFriend() + )); + } + + $product = $this->getProductFromRepository($args['input']['params']['product_id']); + $senderArray = $this->getSenderArrayFromArgs($args); + $recipientsArray = $this->getRecipientsArray($args); + //@todo clarify if event should be dispatched + //$this->_eventManager->dispatch('sendfriend_product', ['product' => $product]); + $this->sendFriend->setSender($senderArray); + $this->sendFriend->setRecipients($recipientsArray); + $this->sendFriend->setProduct($product); + + $this->prepareDataForValidation($args, $recipientsArray); + $validationResult = $this->sendFriend->validate(); + $this->addRecipientNameValidation($args); + if ($validationResult !== true) { + throw new GraphQlInputException(__(implode($validationResult))); + } + + $this->sendFriend->send(); + + return array_merge($senderArray, $recipientsArray); + } + + private function prepareDataForValidation(array $args, array $recipientsArray): void + { + $sender = $this->dataObjectFactory->create()->setData([ + 'name' => $args['input']['sender']['name'], + 'email'=> $args['input']['sender']['email'], + 'message' => $args['input']['sender']['message'], + ]); + $emails = []; + foreach ($recipientsArray['recipients'] as $recipient) { + $emails[] = $recipient['email']; + } + $recipients = $this->dataObjectFactory->create()->setData('emails', $emails); + + $this->sendFriend->setData('_sender', $sender); + $this->sendFriend->setData('_recipients', $recipients); + } + + /** + * @param array $args + * @throws GraphQlInputException + */ + private function addRecipientNameValidation(array $args): void + { + foreach ($args['input']['recipients'] as $recipient) { + if (empty($recipient['name'])) { + throw new GraphQlInputException( + __('Please Provide Name for Recipient with this Email Address: ' . $recipient['email'] + )); + } + } + } + + /** + * @param int $productId + * @return bool|\Magento\Catalog\Api\Data\ProductInterface + */ + private function getProductFromRepository(int $productId) + { + try { + $product = $this->productRepository->getById($productId); + if (!$product->isVisibleInCatalog()) { + return false; + } + } catch (NoSuchEntityException $noEntityException) { + return false; + } + + return $product; + } + + private function getRecipientsArray(array $args): array + { + $recipientsArray = []; + foreach ($args['input']['recipients'] as $recipient) { + $recipientsArray[] = [ + 'name' => $recipient['name'], + 'email' => $recipient['email'], + ]; + } + return ['recipients' => $recipientsArray]; + } + + private function getSenderArrayFromArgs(array $args): array + { + return ['sender' => [ + 'name' => $args['input']['sender']['name'], + 'email' => $args['input']['sender']['email'], + 'message' => $args['input']['sender']['message'], + ] + ]; + } +} diff --git a/app/code/Magento/SendFriendGraphQl/etc/module.xml b/app/code/Magento/SendFriendGraphQl/etc/module.xml new file mode 100644 index 0000000000000..14d792198cd5f --- /dev/null +++ b/app/code/Magento/SendFriendGraphQl/etc/module.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls b/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls new file mode 100644 index 0000000000000..87bf90fd10072 --- /dev/null +++ b/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls @@ -0,0 +1,33 @@ +# Copyright © Magento, Inc. All rights reserved. +# See COPYING.txt for license details. + +type Mutation { + sendEmailToFriend (input: SendEmailToFriendSenderInput): SendEmailToFriendOutput @resolver(class: "\\Magento\\SendFriendGraphQl\\Model\\Resolver\\SendEmailToFriend") @doc(description:"@todo") +} + +input SendEmailToFriendSenderInput { + sender: Sender! + params: Params! + recipients: [Recipient] +} + +type Sender { + name: String! + email: String! + message: String! +} +#@todo Prams can be removed if dispatching of event in app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php not needed +type Params { + product_id: Int! +} + +type Recipient { + name: String! + email: String! +} + + +type SendEmailToFriendOutput { + sender: Sender + recipients: [Recipient] +} diff --git a/app/code/Magento/SendFriendGraphQl/registration.php b/app/code/Magento/SendFriendGraphQl/registration.php new file mode 100644 index 0000000000000..c41607a0dc864 --- /dev/null +++ b/app/code/Magento/SendFriendGraphQl/registration.php @@ -0,0 +1,9 @@ + Date: Fri, 26 Oct 2018 18:23:15 +0300 Subject: [PATCH 0325/1158] MAGETWO-95687: Remove old implementation of customer addresses tab --- .../Adminhtml/Edit/Address/CancelButton.php | 2 +- .../Adminhtml/Edit/Address/SaveButton.php | 2 +- .../Controller/Adminhtml/Address/Save.php | 3 +- .../Controller/Adminhtml/Address/Validate.php | 4 +-- .../Controller/Adminhtml/Index/Save.php | 2 ++ .../Controller/Adminhtml/Index/Validate.php | 3 ++ .../Customer/Model/Address/DataProvider.php | 31 +++++-------------- .../Customer/Model/Customer/DataProvider.php | 1 + .../DataProviderWithDefaultAddresses.php | 20 +----------- .../Customer/Model/Metadata/Form/File.php | 17 +++++----- .../ResourceModel/Address/Grid/Collection.php | 4 +-- .../Test/Unit/Controller/Address/SaveTest.php | 2 -- .../Unit/Model/Customer/DataProviderTest.php | 1 + .../Magento/Ui/Component/Form/Fieldset.php | 2 ++ 14 files changed, 34 insertions(+), 60 deletions(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php index 80d9780f819d0..6270e8073d0e8 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php @@ -14,7 +14,7 @@ class CancelButton extends GenericButton implements ButtonProviderInterface { /** - * {@inheritdoc} + * @inheritdoc * * @return array */ diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php index 706ef32c9e5a5..0d3a9f57ff5a3 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php @@ -14,7 +14,7 @@ class SaveButton extends GenericButton implements ButtonProviderInterface { /** - * {@inheritdoc} + * @inheritdoc * * @return array */ diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index df041ac4e1202..e1d605a8d0890 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -135,7 +135,8 @@ public function execute(): Redirect $this->logger->critical($e); } catch (\Exception $e) { $this->messageManager->addExceptionMessage( - $e, __('We can\'t change customer address right now.') + $e, + __('We can\'t change customer address right now.') ); } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php index 01ce720a20e63..696bf3099db11 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -33,9 +33,9 @@ class Validate extends \Magento\Backend\App\Action implements HttpPostActionInte private $formFactory; /** - * @param Action\Context $context + * @param Action\Context $context * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory - * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory + * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory */ public function __construct( Action\Context $context, diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php index aed7908337ee1..d80c712914ef0 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php @@ -15,6 +15,8 @@ use Magento\Framework\Exception\LocalizedException; /** + * Save customer action. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Save extends \Magento\Customer\Controller\Adminhtml\Index implements HttpPostActionInterface diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php index 67adf98d6c718..d91bc7424bffe 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php @@ -11,6 +11,9 @@ use Magento\Framework\Message\Error; use Magento\Customer\Controller\Adminhtml\Index as CustomerAction; +/** + * Class for validation of customer + */ class Validate extends CustomerAction implements HttpPostActionInterface, HttpGetActionInterface { /** diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 34f4b8b4eca89..c92cd731db743 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -27,9 +27,9 @@ use Magento\Customer\Model\FileProcessorFactory; /** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * * Dataprovider for customer address grid. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider { @@ -53,11 +53,6 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $loadedData; - /** - * @var Config - */ - private $eavConfig; - /** * EAV attribute properties to fetch from meta storage * @var array @@ -154,6 +149,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param ContextInterface $context * @param FileProcessorFactory $fileProcessorFactory * @param \Magento\Customer\Model\Config\Share $shareConfig + * @param CountryWithWebsites $countryWithWebsites * @param array $meta * @param array $data * @param bool $allowToShowHiddenAttributes @@ -170,6 +166,7 @@ public function __construct( ContextInterface $context, FileProcessorFactory $fileProcessorFactory, \Magento\Customer\Model\Config\Share $shareConfig, + CountryWithWebsites $countryWithWebsites, array $meta = [], array $data = [], $allowToShowHiddenAttributes = true @@ -182,6 +179,7 @@ public function __construct( $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; $this->context = $context; $this->fileProcessorFactory = $fileProcessorFactory; + $this->countryWithWebsiteSource = $countryWithWebsites; $this->shareConfig = $shareConfig; $this->meta['general']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer_address') @@ -323,7 +321,7 @@ protected function getAttributesMeta(Type $entityType): array if ($attribute->usesSource()) { if ($code == AddressInterface::COUNTRY_ID) { - $meta[$code]['arguments']['data']['config']['options'] = $this->getCountryWithWebsiteSource() + $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource ->getAllOptions(); } else { $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); @@ -364,25 +362,10 @@ private function processFrontendInput(AttributeInterface $attribute, array &$met } } - /** - * Retrieve Country With Websites Source - * - * @return CountryWithWebsites - * @deprecated 100.2.0 - */ - private function getCountryWithWebsiteSource(): CountryWithWebsites - { - if (!$this->countryWithWebsiteSource) { - $this->countryWithWebsiteSource = ObjectManager::getInstance()->get(CountryWithWebsites::class); - } - - return $this->countryWithWebsiteSource; - } - /** * Detect can we show attribute on specific form or not * - * @param Attribute $customerAttribute + * @param AbstractAttribute $customerAttribute * @return bool */ private function canShowAttribute(AbstractAttribute $customerAttribute): bool diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index ce976d3f62c74..c834dd26824cd 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -31,6 +31,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * + * @deprecated \Magento\Customer\Model\Address\DataProvider is used instead * @api * @since 100.0.2 */ diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index d52c94fb034c6..2e47787b9adbc 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -186,9 +186,6 @@ public function __construct( $this->meta['customer']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer') ); -// $this->meta['address']['children'] = $this->getAttributesMeta( -// $eavConfig->getEntityType('customer_address') -// ); } /** @@ -300,7 +297,7 @@ private function getFileUploaderData( $file = $customerData[$attributeCode] ?? ''; /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->getFileProcessorFactory()->create([ + $fileProcessor = $this->fileProcessorFactory->create([ 'entityTypeCode' => $entityType->getEntityTypeCode(), ]); @@ -567,19 +564,4 @@ protected function prepareAddressData($addressId, array &$addresses, array $cust $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); } } - - /** - * Get FileProcessorFactory instance - * - * @return FileProcessorFactory - * @deprecated 100.1.3 - */ - private function getFileProcessorFactory(): FileProcessorFactory - { - if ($this->fileProcessorFactory === null) { - $this->fileProcessorFactory = ObjectManager::getInstance() - ->get(\Magento\Customer\Model\FileProcessorFactory::class); - } - return $this->fileProcessorFactory; - } } diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index aca5b277186ca..b9bec01f9ba7c 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -15,6 +15,8 @@ use Magento\Framework\Filesystem; /** + * Processes files that are save for customer. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class File extends AbstractData @@ -66,7 +68,7 @@ class File extends AbstractData * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param null $value + * @param array|string $value * @param string $entityTypeCode * @param bool $isAjax * @param \Magento\Framework\Url\EncoderInterface $urlEncoder @@ -101,7 +103,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function extractValue(\Magento\Framework\App\RequestInterface $request) @@ -160,8 +162,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) } /** - * Validate file by attribute validate rules - * Return array of errors + * Validate file by attribute validate rules. Returns array of errors. * * @param array $value * @return string[] @@ -232,7 +233,7 @@ protected function _isUploadedFile($filename) } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -273,7 +274,7 @@ public function validateValue($value) } /** - * {@inheritdoc} + * @inheritdoc * * @return ImageContentInterface|array|string|null */ @@ -358,7 +359,7 @@ protected function processInputFieldValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function restoreValue($value) { @@ -366,7 +367,7 @@ public function restoreValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function outputValue($format = \Magento\Customer\Model\Metadata\ElementFactory::OUTPUT_FORMAT_TEXT) { diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php index 83129fee9b59b..8026349563867 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -92,7 +92,7 @@ protected function _initSelect() } /** - * {@inheritdoc} + * @inheritdoc * * @return AggregationInterface */ @@ -102,7 +102,7 @@ public function getAggregations() } /** - * {@inheritdoc} + * @inheritdoc * * @param AggregationInterface $aggregations * @return $this diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php index 47088eece23ed..863ce260ab68c 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php @@ -24,7 +24,6 @@ class SaveTest extends \PHPUnit\Framework\TestCase */ private $addressRepositoryMock; - /** * @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject */ @@ -65,7 +64,6 @@ class SaveTest extends \PHPUnit\Framework\TestCase */ private $messageManagerMock; - /** * @inheritdoc */ diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php index 50c21379054bf..bf6d3f0f9bbc5 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php @@ -21,6 +21,7 @@ * * Test for class \Magento\Customer\Model\Customer\DataProvider * + * @deprecated tested class is not used. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataProviderTest extends \PHPUnit\Framework\TestCase diff --git a/app/code/Magento/Ui/Component/Form/Fieldset.php b/app/code/Magento/Ui/Component/Form/Fieldset.php index ebfe58f3abb89..ef115fe459eba 100644 --- a/app/code/Magento/Ui/Component/Form/Fieldset.php +++ b/app/code/Magento/Ui/Component/Form/Fieldset.php @@ -8,6 +8,8 @@ use Magento\Ui\Component\AbstractComponent; /** + * Fieldset UI Component. + * * @api * @since 100.0.2 */ From dc506771ce4353b0d3a272368acd7322dbf391c8 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 19:16:12 +0300 Subject: [PATCH 0326/1158] MAGETWO-95687: Remove old implementation of customer addresses tab --- .../Customer/Model/Address/DataProvider.php | 2 +- .../DataProviderWithDefaultAddresses.php | 25 ------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index c92cd731db743..7f23deddd89a6 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -384,7 +384,7 @@ private function canShowAttribute(AbstractAttribute $customerAttribute): bool /** * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... * - * @param Attribute $customerAttribute + * @param AbstractAttribute $customerAttribute * @return bool */ private function canShowAttributeInForm(AbstractAttribute $customerAttribute): bool diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 2e47787b9adbc..7ba6484dc3f2b 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -539,29 +539,4 @@ private function processFrontendInput(AttributeInterface $attribute, array &$met ]; } } - - /** - * Prepare address data - * - * @param int $addressId - * @param array $addresses - * @param array $customer - * @return void - */ - protected function prepareAddressData($addressId, array &$addresses, array $customer) - { - if (isset($customer['default_billing']) - && $addressId == $customer['default_billing'] - ) { - $addresses[$addressId]['default_billing'] = $customer['default_billing']; - } - if (isset($customer['default_shipping']) - && $addressId == $customer['default_shipping'] - ) { - $addresses[$addressId]['default_shipping'] = $customer['default_shipping']; - } - if (isset($addresses[$addressId]['street']) && !\is_array($addresses[$addressId]['street'])) { - $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); - } - } } From 9a7fa4c650dd41151d986486a02dd58d4c6cc2ff Mon Sep 17 00:00:00 2001 From: Max Almonte Date: Fri, 26 Oct 2018 12:26:08 -0400 Subject: [PATCH 0327/1158] Added $_regionCollection property to class --- .../Magento/CustomerImportExport/Model/Import/Address.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php index e1345edcf146d..9ba50738ebc1a 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php @@ -101,6 +101,13 @@ class Address extends AbstractCustomer */ protected $_entityTable; + /** + * Region collection instance + * + * @var string + */ + protected $_regionCollection; + /** * Countries and regions * From ac90f7a0be57d6d4240e64ac7fd98aeafeb80045 Mon Sep 17 00:00:00 2001 From: Max Almonte Date: Fri, 26 Oct 2018 12:52:10 -0400 Subject: [PATCH 0328/1158] Added $connection property to class --- .../Magento/DownloadableImportExport/Helper/Uploader.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php index 46081f77cc66a..9420aeb51d41c 100644 --- a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php +++ b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php @@ -38,6 +38,13 @@ class Uploader extends \Magento\Framework\App\Helper\AbstractHelper */ protected $parameters = []; + /** + * Connection resource. + * + * @var \Magento\Framework\DB\Adapter\AdapterInterface + */ + protected $connection = []; + /** * Construct * From e3df0f684ac20c478685cc601590e5231a531eb1 Mon Sep 17 00:00:00 2001 From: Max Almonte Date: Fri, 26 Oct 2018 13:12:37 -0400 Subject: [PATCH 0329/1158] Fixed miss called property in getStoreIdByCode method --- .../BundleImportExport/Model/Import/Product/Type/Bundle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index 3ed7e144ddd5a..77d331a8b5696 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -779,7 +779,7 @@ protected function clear() */ private function getStoreIdByCode(string $storeCode): int { - if (!isset($this->storeIdToCode[$storeCode])) { + if (!isset($this->storeCodeToId[$storeCode])) { /** @var $store \Magento\Store\Model\Store */ foreach ($this->storeManager->getStores() as $store) { $this->storeCodeToId[$store->getCode()] = $store->getId(); From 5181674d525cc5e39482ac443ea3ac2b1a6c9bd0 Mon Sep 17 00:00:00 2001 From: Max Almonte Date: Fri, 26 Oct 2018 13:28:40 -0400 Subject: [PATCH 0330/1158] Added $_customerCollection property to Storage class --- .../Model/ResourceModel/Import/Customer/Storage.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php index f779505a38011..38890de643295 100644 --- a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php +++ b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php @@ -48,6 +48,13 @@ class Storage */ private $customerCollectionFactory; + /** + * Customer collection. + * + * @var \Magento\Customer\Model\ResourceModel\Customer\Collection + */ + private $_customerCollection; + /** * @param CustomerCollectionFactory $collectionFactory * @param CollectionByPagesIteratorFactory $colIteratorFactory From 2054fab1731a63728a6b4e573cefbbf3e64d6c85 Mon Sep 17 00:00:00 2001 From: Rus0 Date: Fri, 26 Oct 2018 16:25:02 -0500 Subject: [PATCH 0331/1158] Autoload for root folders --- app/autoload.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/autoload.php b/app/autoload.php index 54087d0255495..d6407083dc0b3 100644 --- a/app/autoload.php +++ b/app/autoload.php @@ -28,6 +28,9 @@ /* 'composer install' validation */ if (file_exists($vendorAutoload)) { $composerAutoloader = include $vendorAutoload; +} else if (file_exists("{$vendorDir}/autoload.php")) { + $vendorAutoload = "{$vendorDir}/autoload.php"; + $composerAutoloader = include $vendorAutoload; } else { throw new \Exception( 'Vendor autoload is not found. Please run \'composer install\' under application root directory.' From cd243969b796e658edd844a3fe91d43cb308f72a Mon Sep 17 00:00:00 2001 From: saphal Date: Sat, 27 Oct 2018 15:42:40 +0530 Subject: [PATCH 0332/1158] #18192, Fixed rating issue website wise --- .../Review/Model/ResourceModel/Rating.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating.php b/app/code/Magento/Review/Model/ResourceModel/Rating.php index 3f54c17f6ff7c..5232a7fa33af4 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating.php @@ -34,12 +34,18 @@ class Rating extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb */ protected $_logger; + /** + * @var \Magento\Framework\App\State + */ + protected $_state; + /** * @param \Magento\Framework\Model\ResourceModel\Db\Context $context * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Module\Manager $moduleManager * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Review\Model\ResourceModel\Review\Summary $reviewSummary + * @param \Magento\Framework\App\State * @param string $connectionName */ public function __construct( @@ -48,12 +54,14 @@ public function __construct( \Magento\Framework\Module\Manager $moduleManager, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Review\Model\ResourceModel\Review\Summary $reviewSummary, + \Magento\Framework\App\State $state, $connectionName = null ) { $this->moduleManager = $moduleManager; $this->_storeManager = $storeManager; $this->_logger = $logger; $this->_reviewSummary = $reviewSummary; + $this->_state = $state; parent::__construct($context, $connectionName); } @@ -425,9 +433,15 @@ public function getReviewSummary($object, $onlyForCurrentStore = true) $data = $connection->fetchAll($select, [':review_id' => $object->getReviewId()]); + if ($this->_state->getAreaCode() == "adminhtml") { + $currentStore = false; + } else { + $currentStore = $this->_storeManager->getStore()->setId(); + } + if ($onlyForCurrentStore) { foreach ($data as $row) { - if ($row['store_id'] == $this->_storeManager->getStore()->getId()) { + if ($row['store_id'] == $currentStore) { $object->addData($row); } } From cbbaf120f228d4499bdb7ead40a26f6a2f1c2330 Mon Sep 17 00:00:00 2001 From: saphal Date: Sat, 27 Oct 2018 18:51:56 +0530 Subject: [PATCH 0333/1158] updated code as per given instruction --- app/code/Magento/Review/Model/ResourceModel/Rating.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating.php b/app/code/Magento/Review/Model/ResourceModel/Rating.php index 5232a7fa33af4..79609a9afe41f 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating.php @@ -433,10 +433,9 @@ public function getReviewSummary($object, $onlyForCurrentStore = true) $data = $connection->fetchAll($select, [':review_id' => $object->getReviewId()]); + $currentStore = $this->_storeManager->getStore()->setId(); if ($this->_state->getAreaCode() == "adminhtml") { $currentStore = false; - } else { - $currentStore = $this->_storeManager->getStore()->setId(); } if ($onlyForCurrentStore) { From 4a283722cdb25ef030d8100bc20c3fa16c2e3d91 Mon Sep 17 00:00:00 2001 From: Artem Klimov Date: Sat, 27 Oct 2018 19:36:06 +0300 Subject: [PATCH 0334/1158] resolve magento 2.3 update conflicts --- lib/internal/Magento/Framework/GraphQl/Config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index bfd8f330c6123..481d75ed35893 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -10,6 +10,7 @@ use Magento\Framework\Config\DataInterface; use Magento\Framework\GraphQl\Config\ConfigElementFactoryInterface; use Magento\Framework\GraphQl\Config\ConfigElementInterface; +use Magento\Framework\GraphQl\Query\Fields as QueryFields; /** * Provides access to typing information for a configured GraphQL schema. From b8d2663b72438fdda17dcd793c349681a5c784c6 Mon Sep 17 00:00:00 2001 From: Artem Klimov Date: Sat, 27 Oct 2018 19:45:50 +0300 Subject: [PATCH 0335/1158] resolve magento 2.3 update conflicts --- lib/internal/Magento/Framework/GraphQl/Config.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index 481d75ed35893..75b6c64e9d24f 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -65,10 +65,12 @@ public function getConfigElement(string $configElementName) : ConfigElementInter } $fieldsInQuery = $this->queryFields->getFieldsUsedInQuery(); - if (isset($data['fields']) && !empty($fieldsInQuery)) { - foreach ($data['fields'] as $fieldName => $fieldConfig) { - if (!isset($fieldsInQuery[$fieldName])) { - unset($data['fields'][$fieldName]); + if (isset($data['fields'])) { + if (!empty($fieldsInQuery)) { + foreach ($data['fields'] as $fieldName => $fieldConfig) { + if (!isset($fieldsInQuery[$fieldName])) { + unset($data['fields'][$fieldName]); + } } } From 3ba63db9b7fc2e1acad4d8d1c416399c471dfcea Mon Sep 17 00:00:00 2001 From: Vital_Pantsialeyeu Date: Sun, 28 Oct 2018 05:22:49 +0300 Subject: [PATCH 0336/1158] MAGETWO-95826: Zoomed part of images becomes distorted in case when image width/height ratio has ~2x difference - Changed the logic of calculating the coefficient of zoom --- lib/web/mage/gallery/gallery.less | 1 + lib/web/magnifier/magnifier.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less index 3c35a772253bc..ebd6bdd003b81 100644 --- a/lib/web/mage/gallery/gallery.less +++ b/lib/web/mage/gallery/gallery.less @@ -764,6 +764,7 @@ max-width: inherit; position: absolute; top: 0; + object-fit: scale-down; } } diff --git a/lib/web/magnifier/magnifier.js b/lib/web/magnifier/magnifier.js index 150c8adf0b22b..a65fcd4669d80 100644 --- a/lib/web/magnifier/magnifier.js +++ b/lib/web/magnifier/magnifier.js @@ -542,7 +542,11 @@ showWrapper = true; bindEvents(eventType, thumb); data[idx].status = 2; - data[idx].zoom = largeObj.height / largeWrapper.height(); + if (largeObj.width > largeObj.height) { + data[idx].zoom = largeObj.width / largeWrapper.width(); + } else { + data[idx].zoom = largeObj.height / largeWrapper.height(); + } setThumbData(thumb, data[idx]); updateLensOnLoad(idx, thumb, largeObj, largeWrapper); } From dba69444975fab128a0764e4516af29331624e68 Mon Sep 17 00:00:00 2001 From: Dmytro Cheshun Date: Sun, 28 Oct 2018 11:42:31 +0200 Subject: [PATCH 0337/1158] Add missing unit test for WishlistSettings plugin --- .../Ui/DataProvider/WishlistSettingsTest.php | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 app/code/Magento/Wishlist/Test/Unit/Plugin/Ui/DataProvider/WishlistSettingsTest.php diff --git a/app/code/Magento/Wishlist/Test/Unit/Plugin/Ui/DataProvider/WishlistSettingsTest.php b/app/code/Magento/Wishlist/Test/Unit/Plugin/Ui/DataProvider/WishlistSettingsTest.php new file mode 100644 index 0000000000000..aa3b956e12153 --- /dev/null +++ b/app/code/Magento/Wishlist/Test/Unit/Plugin/Ui/DataProvider/WishlistSettingsTest.php @@ -0,0 +1,59 @@ +helperMock = $this->createMock(Data::class); + $this->wishlistSettings = new WishlistSettings($this->helperMock); + } + + /** + * Test afterGetData method + * + * @return void + */ + public function testAfterGetData() + { + /** @var DataProvider|\PHPUnit_Framework_MockObject_MockObject $subjectMock */ + $subjectMock = $this->createMock(DataProvider::class); + $result = []; + $isAllow = true; + $this->helperMock->expects($this->once())->method('isAllow')->willReturn(true); + + $expected = ['allowWishlist' => $isAllow]; + $actual = $this->wishlistSettings->afterGetData($subjectMock, $result); + self::assertEquals($expected, $actual); + } +} From 22abbcbb6ac21b32ca25b93f55bba8079a2d56c9 Mon Sep 17 00:00:00 2001 From: rahul Date: Sun, 28 Oct 2018 15:37:38 +0530 Subject: [PATCH 0338/1158] fixed - can't import external http to https redirecting images by default csv import --- lib/internal/Magento/Framework/Filesystem/Driver/Http.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php index 236585fa61384..e43f35b072f1d 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php @@ -36,6 +36,11 @@ public function isExists($path) $status = $headers[0]; + /* Handling 302 redirection */ + if (strpos($status, '302 Found') !== false && isset($headers[1])) { + $status = $headers[1]; + } + if (strpos($status, '200 OK') === false) { $result = false; } else { From b0240f1588f6e4458a59d01e70c5d8d51d98aca4 Mon Sep 17 00:00:00 2001 From: Denis Papec Date: Sun, 28 Oct 2018 20:04:33 +0000 Subject: [PATCH 0339/1158] Clean Up Magento/ImportExport/Controller/Adminhtml/History/Download --- .../ImportExport/Controller/Adminhtml/History/Download.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php b/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php index e490ee4018376..4dda5ebc4a310 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php @@ -15,6 +15,11 @@ class Download extends \Magento\ImportExport\Controller\Adminhtml\History */ protected $resultRawFactory; + /** + * @var \Magento\Framework\App\Response\Http\FileFactory + */ + private $fileFactory; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory From dd8625e19b5e50d49f28a645a2a89b680be9bef6 Mon Sep 17 00:00:00 2001 From: Denis Papec Date: Sun, 28 Oct 2018 21:02:49 +0000 Subject: [PATCH 0340/1158] Define $session propery --- app/code/Magento/ImportExport/Model/History.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/ImportExport/Model/History.php b/app/code/Magento/ImportExport/Model/History.php index 3138f150d5fc5..617ca11e18f22 100644 --- a/app/code/Magento/ImportExport/Model/History.php +++ b/app/code/Magento/ImportExport/Model/History.php @@ -42,6 +42,11 @@ class History extends \Magento\Framework\Model\AbstractModel */ protected $reportHelper; + /** + * @var \Magento\Backend\Model\Auth\Session + */ + private $session; + /** * Class constructor * From 611969d9a56905613aefb981c8cd4be7efc24330 Mon Sep 17 00:00:00 2001 From: saphal Date: Mon, 29 Oct 2018 11:04:31 +0530 Subject: [PATCH 0341/1158] code modification --- app/code/Magento/Review/Model/ResourceModel/Rating.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating.php b/app/code/Magento/Review/Model/ResourceModel/Rating.php index 79609a9afe41f..debaf61c4dd4b 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating.php @@ -433,10 +433,7 @@ public function getReviewSummary($object, $onlyForCurrentStore = true) $data = $connection->fetchAll($select, [':review_id' => $object->getReviewId()]); - $currentStore = $this->_storeManager->getStore()->setId(); - if ($this->_state->getAreaCode() == "adminhtml") { - $currentStore = false; - } + $currentStore = ($this->_state->getAreaCode() == "adminhtml") ? false : $this->_storeManager->getStore()->getId(); if ($onlyForCurrentStore) { foreach ($data as $row) { From 5854ca32e8536be9cb0ffb9dce44c0c38ecde6e0 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Mon, 29 Oct 2018 10:10:02 +0300 Subject: [PATCH 0342/1158] MAGETWO-95809: Item row total display incorrect value in API response - Changing row total in webapi response --- .../Sales/Plugin/DataObjectProcessor.php | 55 ++++++++++++++ app/code/Magento/Sales/etc/webapi_rest/di.xml | 3 + app/code/Magento/Sales/etc/webapi_soap/di.xml | 3 + .../Sales/Service/V1/OrderItemGetTest.php | 30 ++++++++ .../Sales/_files/order_with_discount.php | 71 +++++++++++++++++++ .../_files/order_with_discount_rollback.php | 8 +++ 6 files changed, 170 insertions(+) create mode 100644 app/code/Magento/Sales/Plugin/DataObjectProcessor.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount_rollback.php diff --git a/app/code/Magento/Sales/Plugin/DataObjectProcessor.php b/app/code/Magento/Sales/Plugin/DataObjectProcessor.php new file mode 100644 index 0000000000000..5c61cdda9efc2 --- /dev/null +++ b/app/code/Magento/Sales/Plugin/DataObjectProcessor.php @@ -0,0 +1,55 @@ +priceRenderer = $priceRenderer; + } + + /** + * Changing row total for webapi order item response. + * + * @param Subject $subject + * @param array $result + * @param mixed $dataObject + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterBuildOutputDataArray( + Subject $subject, + $result, + $dataObject + ) { + if ($dataObject instanceof OrderItem) { + $result[OrderItemInterface::ROW_TOTAL] = $this->priceRenderer->getTotalAmount($dataObject); + $result[OrderItemInterface::BASE_ROW_TOTAL] = $this->priceRenderer->getBaseTotalAmount($dataObject); + } + + return $result; + } +} diff --git a/app/code/Magento/Sales/etc/webapi_rest/di.xml b/app/code/Magento/Sales/etc/webapi_rest/di.xml index 47fb3f188513c..70fe957673517 100644 --- a/app/code/Magento/Sales/etc/webapi_rest/di.xml +++ b/app/code/Magento/Sales/etc/webapi_rest/di.xml @@ -15,4 +15,7 @@ + + + diff --git a/app/code/Magento/Sales/etc/webapi_soap/di.xml b/app/code/Magento/Sales/etc/webapi_soap/di.xml index 47fb3f188513c..70fe957673517 100644 --- a/app/code/Magento/Sales/etc/webapi_soap/di.xml +++ b/app/code/Magento/Sales/etc/webapi_soap/di.xml @@ -15,4 +15,7 @@ + + + diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderItemGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderItemGetTest.php index 3ab93f9aecb99..592bdf3d584a9 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderItemGetTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderItemGetTest.php @@ -77,4 +77,34 @@ protected function assertOrderItem(\Magento\Sales\Model\Order\Item $orderItem, a $this->assertEquals($orderItem->getBasePrice(), $response['base_price']); $this->assertEquals($orderItem->getRowTotal(), $response['row_total']); } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order_with_discount.php + */ + public function testGetOrderWithDiscount() + { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId(self::ORDER_INCREMENT_ID); + /** @var \Magento\Sales\Model\Order\Item $orderItem */ + $orderItem = current($order->getItems()); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $orderItem->getId(), + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'get', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['id' => $orderItem->getId()]); + + $this->assertTrue(is_array($response)); + $this->assertEquals(8.00, $response['row_total']); + $this->assertEquals(8.00, $response['base_row_total']); + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount.php new file mode 100644 index 0000000000000..a83b01589ea9c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount.php @@ -0,0 +1,71 @@ +create(OrderAddress::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +/** @var Payment $payment */ +$payment = $objectManager->create(Payment::class); +$payment->setMethod('checkmo') + ->setAdditionalInformation('last_trans_id', '11122') + ->setAdditionalInformation( + 'metadata', + [ + 'type' => 'free', + 'fraudulent' => false, + ] + ); + +/** @var OrderItem $orderItem */ +$orderItem = $objectManager->create(OrderItem::class); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType('simple') + ->setDiscountAmount(2) + ->setBaseRowTotal($product->getPrice()) + ->setBaseDiscountAmount(2); + +/** @var Order $order */ +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000001') + ->setState(Order::STATE_PROCESSING) + ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) + ->setSubtotal(100) + ->setGrandTotal(100) + ->setBaseSubtotal(100) + ->setBaseGrandTotal(100) + ->setCustomerIsGuest(true) + ->setCustomerEmail('customer@null.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setStoreId($objectManager->get(StoreManagerInterface::class)->getStore()->getId()) + ->addItem($orderItem) + ->setPayment($payment); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->create(OrderRepositoryInterface::class); +$orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount_rollback.php new file mode 100644 index 0000000000000..1fb4b4636ab29 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_discount_rollback.php @@ -0,0 +1,8 @@ + Date: Mon, 29 Oct 2018 11:44:03 +0400 Subject: [PATCH 0343/1158] MAGETWO-95830: Cannot create credit memo if the used in the order cart rule is deleted - Add automated test --- ...reateCreditMemoWhenCartRuleDeletedTest.xml | 109 ++++++++++++++++++ .../AdminCreateCartPriceRuleActionGroup.xml | 16 ++- 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml new file mode 100644 index 0000000000000..6ca7c838b7fe7 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml @@ -0,0 +1,109 @@ + + + + + + + + + + <description value="Verify Credit Memo created if the used in the order cart rule is deleted"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95894"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="product"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <!-- Create Cart Price Rule with a specific coupon --> + <actionGroup ref="AdminCreateCartPriceRuleWithCouponCode" stepKey="createCartPriceRule"> + <argument name="ruleName" value="TestSalesRule"/> + <argument name="couponCode" value="_defaultCoupon.code"/> + </actionGroup> + + <!--Go to Storefront. Add product to cart--> + <amOnPage url="/$$product.name$$.html" stepKey="GoToProduct"/> + <actionGroup ref="StorefrontAddToCartCustomOptionsProductPageActionGroup" stepKey="AddProductToCard"> + <argument name="productName" value="$$product.name$$"/> + </actionGroup> + <!--Proceed to checkout--> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> + <click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + + <click selector="{{DiscountSection.DiscountTab}}" stepKey="clickToAddDiscount"/> + <fillField selector="{{DiscountSection.DiscountInput}}" userInput="{{_defaultCoupon.code}}" stepKey="TypeDiscountCode"/> + <click selector="{{DiscountSection.ApplyCodeBtn}}" stepKey="clickToApplyDiscount"/> + <waitForPageLoad stepKey="WaitForDiscountToBeAdded"/> + <see userInput="Your coupon was successfully applied." stepKey="verifyText"/> + + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + + <!--Proceed to Admin panel > SALES > Orders. Created order should be in Processing status--> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrdersIndexPage"/> + <waitForPageLoad stepKey="waitForOrderIndexPage"/> + + <!-- Open Order --> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <waitForPageLoad stepKey="waitForCreatedOrderPageOpened"/> + + <!--Click *Invoice* button--> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceButton"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seeNewInvoiceInPageTitle" after="clickInvoiceButton"/> + <waitForPageLoad stepKey="waitForInvoicePageOpened"/> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <waitForPageLoad stepKey="waitForInvoiceSaved"/> + <see userInput="The invoice has been created." stepKey="seeCorrectMessage"/> + + <!-- Delete the cart price rule --> + <actionGroup ref="DeleteCartPriceRuleByName" stepKey="deleteCartPriceRule"> + <argument name="ruleName" value="{{TestSalesRule.name}}"/> + </actionGroup> + + <!--Proceed to Admin panel > SALES > Orders. Created order should be in Processing status--> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrdersIndexPage2"/> + <waitForPageLoad stepKey="waitForOrderIndexPage2"/> + + <!-- Open Order --> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById2"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow2"/> + <waitForPageLoad stepKey="waitForCreatedOrderPageOpened2"/> + + <!--Admin create credit memo for order--> + <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment"/> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreditMemoAction"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline"/> + + <!--Make sure that Credit memo was created successfully--> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccess"/> + + <after> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logOut"/> + </after> + </test> +</tests> diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml index 87947fba8095a..a8dc13d85a360 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml @@ -6,7 +6,7 @@ */ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminCreateCartPriceRuleActionGroup"> <arguments> <argument name="ruleName"/> @@ -23,4 +23,18 @@ <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> </actionGroup> + + <actionGroup name="AdminCreateCartPriceRuleWithCouponCode" extends="AdminCreateCartPriceRuleActionGroup"> + <arguments> + <argument name="couponCode" defaultValue="_defaultCoupon.code"/> + </arguments> + <remove keyForRemoval="selectActionType"/> + <remove keyForRemoval="fillDiscountAmount"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.coupon}}" userInput="Specific Coupon" stepKey="selectCouponType" after="selectCustomerGroup"/> + <waitForElementVisible selector="{{AdminCartPriceRulesFormSection.couponCode}}" stepKey="waitForElementVisible" after="selectCouponType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.couponCode}}" userInput="{{couponCode}}" stepKey="fillCouponCode" after="waitForElementVisible"/> + <fillField selector="{{AdminCartPriceRulesFormSection.userPerCoupon}}" userInput="99" stepKey="fillUserPerCoupon" after="fillCouponCode"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Fixed amount discount for whole cart" stepKey="selectActionTypeToFixed" after="clickToExpandActions"/> + <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="1" stepKey="fillDiscountAmount" after="selectActionTypeToFixed"/> + </actionGroup> </actionGroups> From 9c617290cf0ae20a2d7b74cb9b2f4dce9204f200 Mon Sep 17 00:00:00 2001 From: David Manners <dmanners87@gmail.com> Date: Mon, 29 Oct 2018 13:45:45 +0000 Subject: [PATCH 0344/1158] magento-engcom/import-export-improvements#54: update codee based on phpcs guidelines --- .../Magento/ImportExport/Model/Import/Entity/AbstractEntity.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php index 74e2c5626236c..1fc3257ff2c1e 100644 --- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php +++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php @@ -830,6 +830,8 @@ public function validateData() } /** + * Get error aggregator object + * * @return ProcessingErrorAggregatorInterface */ public function getErrorAggregator() From 6b2a6d0cf51ac5046408ea599426feb468c10510 Mon Sep 17 00:00:00 2001 From: David Manners <dmanners87@gmail.com> Date: Mon, 29 Oct 2018 13:51:09 +0000 Subject: [PATCH 0345/1158] magento-engcom/import-export-improvements#93: update based on phpcs ruleset --- .../Magento/ImportExport/Controller/Adminhtml/Import/Start.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php index 06b69c512a194..e850f6af86cf9 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php @@ -96,7 +96,7 @@ public function execute() $noticeHtml = $this->historyModel->getSummary(); - if($this->historyModel->getErrorFile()) { + if ($this->historyModel->getErrorFile()) { $noticeHtml .= '<div class="import-error-wrapper">' . __('Only the first 100 errors are shown. ') . '<a href="' . $this->createDownloadUrlImportHistoryFile($this->historyModel->getErrorFile()) From 3d317714b5e5a6d190b1e930726e95501cf03631 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Mon, 29 Oct 2018 16:31:09 +0200 Subject: [PATCH 0346/1158] MAGETWO-94840: Automate with MFTF Managing Advanced Prices from Shared Catalog Page --- .../Mftf/ActionGroup/AdminProductActionGroup.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index 1f6c2ab4bb25f..b637ad1fc358c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -276,4 +276,18 @@ <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> + <!--Check tier price with a discount percentage on product--> + <actionGroup name="AssertDiscountsPercentageOfProducts"> + <arguments> + <argument name="amount" type="string" defaultValue="45"/> + </arguments> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForCustomerGroupPriceAddButton"/> + <grabValueFrom selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" stepKey="grabProductTierPriceInput"/> + <assertEquals stepKey="assertProductTierPriceInput"> + <expectedResult type="string">{{amount}}</expectedResult> + <actualResult type="string">$grabProductTierPriceInput</actualResult> + </assertEquals> + </actionGroup> + </actionGroups> From b552406f8e1bd7cc5b33b37bdc4e8b757883e0de Mon Sep 17 00:00:00 2001 From: David Manners <dmanners87@gmail.com> Date: Mon, 29 Oct 2018 16:45:18 +0000 Subject: [PATCH 0347/1158] magento-engcom/import-export-improvements#134: update file from phpcs feedback --- .../BundleImportExport/Model/Import/Product/Type/Bundle.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index 77d331a8b5696..81a47d72602b7 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -20,6 +20,7 @@ /** * Class Bundle + * * @package Magento\BundleImportExport\Model\Import\Product\Type * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ @@ -349,6 +350,8 @@ protected function populateSelectionTemplate($selection, $optionId, $parentId, $ } /** + * Deprecated method for retrieving mapping between skus and products. + * * @deprecated Misspelled method * @see retrieveProductsByCachedSkus */ @@ -600,6 +603,7 @@ protected function insertOptions() /** * Populate array for insert option values + * * @param array $optionIds * @return array */ From 22594bd6cf742210b2d3b8483702510b25d7fa14 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 29 Oct 2018 11:47:50 -0500 Subject: [PATCH 0348/1158] MAGETWO-95883: [FT] [Klarna] Failed functional tests --- .../Bundle/Test/Block/Adminhtml/Product/Composite/Configure.xml | 1 - .../Test/Block/Adminhtml/Product/Composite/Configure.xml | 1 - .../Test/Block/Adminhtml/Product/Composite/Configure.xml | 1 - 3 files changed, 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.xml index e4c0dce0c5b10..18aedfa97f9eb 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.xml @@ -7,7 +7,6 @@ --> <mapping strict="0"> <fields> - <qty /> <checkbox> <selector>div[contains(@class,"field choice") and label[contains(.,"%product_name%")]]//input</selector> <strategy>xpath</strategy> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml index a66753c2adf23..f7bd155fd2d51 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml @@ -7,7 +7,6 @@ --> <mapping strict="0"> <fields> - <qty /> <attribute> <selector>//div[@class="product-options"]//label[.="%s"]//following-sibling::*//select</selector> <strategy>xpath</strategy> diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.xml index 7a7a6d2124cb7..2f721f05f5ee8 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.xml @@ -7,7 +7,6 @@ --> <mapping strict="0"> <fields> - <qty /> <link> <selector>//*[@id="downloadable-links-list"]/*[contains(.,"%link_name%")]//input</selector> <strategy>xpath</strategy> From c8e0a4f796123b3b4b155bf97a6933d89e0794ae Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 29 Oct 2018 11:48:29 -0500 Subject: [PATCH 0349/1158] MAGETWO-95212: block call to getCurrentUrl method is returning ajax request value - Product list widget can be configured to use a base url for add to cart buttons - Added test section for this scenario --- .../Catalog/Block/Product/AbstractProduct.php | 8 +++++- .../Block/Product/ProductsList.php | 28 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php index 4102c82a0a316..fb45246ea3464 100644 --- a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php +++ b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php @@ -125,6 +125,7 @@ public function __construct(\Magento\Catalog\Block\Product\Context $context, arr /** * Retrieve url for add product to cart + * * Will return product view page URL if product has required options * * @param \Magento\Catalog\Model\Product $product @@ -265,6 +266,7 @@ public function getProductUrl($product, $additional = []) if (!isset($additional['_escape'])) { $additional['_escape'] = true; } + $additional['useUencPlaceholder'] = true; return $product->getUrlModel()->getUrl($product, $additional); } @@ -473,7 +475,9 @@ public function getProductDetailsHtml(\Magento\Catalog\Model\Product $product) } /** - * @param null $type + * Get the renderer that will be used to render the details block + * + * @param string|null $type * @return bool|\Magento\Framework\View\Element\AbstractBlock */ public function getDetailsRenderer($type = null) @@ -489,6 +493,8 @@ public function getDetailsRenderer($type = null) } /** + * Return the list of details + * * @return \Magento\Framework\View\Element\RendererList */ protected function getDetailsRendererList() diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index ed17634aa48c1..2681381c5d771 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -11,11 +11,13 @@ use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Framework\Serialize\Serializer\Json; use Magento\Widget\Block\BlockInterface; +use Magento\Framework\Url\EncoderInterface; /** * Catalog Products List widget block * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ class ProductsList extends \Magento\Catalog\Block\Product\AbstractProduct implements BlockInterface, IdentityInterface { @@ -94,6 +96,11 @@ class ProductsList extends \Magento\Catalog\Block\Product\AbstractProduct implem */ private $json; + /** + * @var \Magento\Framework\Url\EncoderInterface|null + */ + private $urlEncoder; + /** * @param \Magento\Catalog\Block\Product\Context $context * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory @@ -104,6 +111,7 @@ class ProductsList extends \Magento\Catalog\Block\Product\AbstractProduct implem * @param \Magento\Widget\Helper\Conditions $conditionsHelper * @param array $data * @param Json|null $json + * @param \Magento\Framework\Url\EncoderInterface|null $urlEncoder */ public function __construct( \Magento\Catalog\Block\Product\Context $context, @@ -114,7 +122,8 @@ public function __construct( \Magento\CatalogWidget\Model\Rule $rule, \Magento\Widget\Helper\Conditions $conditionsHelper, array $data = [], - Json $json = null + Json $json = null, + EncoderInterface $urlEncoder = null ) { $this->productCollectionFactory = $productCollectionFactory; $this->catalogProductVisibility = $catalogProductVisibility; @@ -123,6 +132,7 @@ public function __construct( $this->rule = $rule; $this->conditionsHelper = $conditionsHelper; $this->json = $json ?: ObjectManager::getInstance()->get(Json::class); + $this->urlEncoder = $urlEncoder ?: ObjectManager::getInstance()->get(EncoderInterface::class); parent::__construct( $context, $data @@ -417,4 +427,20 @@ private function getPriceCurrency() } return $this->priceCurrency; } + + /** + * @inheritdoc + */ + public function getAddToCartUrl($product, $additional = []) + { + $requestingPageUrl = $this->getRequest()->getParam('requesting_page_url'); + + if (!empty($requestingPageUrl)) { + $additional['useUencPlaceholder'] = true; + $url = parent::getAddToCartUrl($product, $additional); + return str_replace('%25uenc%25', $this->urlEncoder->encode($requestingPageUrl), $url); + } + + return parent::getAddToCartUrl($product, $additional); + } } From 9043bc9c755268c63db304a499492867d4c91379 Mon Sep 17 00:00:00 2001 From: Matei Purcaru <matei.purcaru@gmail.com> Date: Mon, 29 Oct 2018 19:59:00 +0200 Subject: [PATCH 0350/1158] magento/graphql-ce#41: Updated global composer.json --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 3f8f0a033c893..ab29199251172 100644 --- a/composer.json +++ b/composer.json @@ -201,6 +201,7 @@ "magento/module-rule": "*", "magento/module-sales": "*", "magento/module-sales-analytics": "*", + "magento/module-sales-graph-ql": "*", "magento/module-sales-inventory": "*", "magento/module-sales-rule": "*", "magento/module-sales-sequence": "*", From e1ac7ceef44e6e5b7db99488850f9dfd8d20e65e Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Mon, 29 Oct 2018 13:14:19 -0500 Subject: [PATCH 0351/1158] MAGETWO-95876: Fatal Error during customer login --- .../Magento/Customer/Model/Authentication.php | 4 +-- .../Customer/Controller/AccountTest.php | 29 ++++++++++++++++ .../Customer/_files/customer_no_password.php | 33 +++++++++++++++++++ .../Framework/Encryption/Encryptor.php | 6 +++- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/_files/customer_no_password.php diff --git a/app/code/Magento/Customer/Model/Authentication.php b/app/code/Magento/Customer/Model/Authentication.php index 0967f1a0189e3..edd98bf9bee0e 100644 --- a/app/code/Magento/Customer/Model/Authentication.php +++ b/app/code/Magento/Customer/Model/Authentication.php @@ -161,12 +161,12 @@ public function isLocked($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function authenticate($customerId, $password) { $customerSecure = $this->customerRegistry->retrieveSecureData($customerId); - $hash = $customerSecure->getPasswordHash(); + $hash = $customerSecure->getPasswordHash() ?? ''; if (!$this->encryptor->validateHash($password, $hash)) { $this->processAuthenticationFailure($customerId); if ($this->isLocked($customerId)) { diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index ed40abd26c0b6..c94948e23ab4d 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -56,6 +56,35 @@ public function testIndexAction() $this->assertContains('Green str, 67', $body); } + /** + * @magentoDataFixture Magento/Customer/_files/customer_no_password.php + */ + public function testLoginWithIncorrectPassword() + { + $expectedMessage = 'The account sign-in was incorrect or your account is disabled temporarily. ' + . 'Please wait and try again later.'; + $this->getRequest() + ->setMethod('POST') + ->setPostValue( + [ + 'login' => [ + 'username' => 'customer@example.com', + 'password' => '123123q' + ] + ] + ); + + $this->dispatch('customer/account/loginPost'); + $this->assertRedirect($this->stringContains('customer/account/login')); + $this->assertSessionMessages( + $this->equalTo( + [ + $expectedMessage + ] + ) + ); + } + /** * Test sign up form displaying. */ diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_no_password.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_no_password.php new file mode 100644 index 0000000000000..0340f0f841ca6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_no_password.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\Customer\Model\CustomerRegistry; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/** @var $repository \Magento\Customer\Api\CustomerRepositoryInterface */ +$repository = $objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); +$customer = $objectManager->create(\Magento\Customer\Model\Customer::class); +/** @var CustomerRegistry $customerRegistry */ +$customerRegistry = $objectManager->get(CustomerRegistry::class); +/** @var Magento\Customer\Model\Customer $customer */ +$customer->setWebsiteId(1) + ->setId(1) + ->setEmail('customer@example.com') + ->setGroupId(1) + ->setStoreId(1) + ->setIsActive(1) + ->setPrefix('Mr.') + ->setFirstname('John') + ->setMiddlename('A') + ->setLastname('Smith') + ->setSuffix('Esq.') + ->setDefaultBilling(1) + ->setDefaultShipping(1) + ->setTaxvat('12') + ->setGender(0); + +$customer->isObjectNew(true); +$customer->save(); +$customerRegistry->remove($customer->getId()); diff --git a/lib/internal/Magento/Framework/Encryption/Encryptor.php b/lib/internal/Magento/Framework/Encryption/Encryptor.php index f7d52d5474ad7..919e710d4f2de 100644 --- a/lib/internal/Magento/Framework/Encryption/Encryptor.php +++ b/lib/internal/Magento/Framework/Encryption/Encryptor.php @@ -263,7 +263,11 @@ private function getPasswordSalt() */ private function getPasswordVersion() { - return array_map('intval', explode(self::DELIMITER, $this->passwordHashMap[self::PASSWORD_VERSION])); + return array_map('intval', explode( + self::DELIMITER, + (string)$this->passwordHashMap[self::PASSWORD_VERSION] + ) + ); } /** From 659e5ffc37c226e21c896a2db4a7e5fbafff8d75 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 29 Oct 2018 13:37:04 -0500 Subject: [PATCH 0352/1158] MAGETWO-95212: block call to getCurrentUrl method is returning ajax request value - Added missing section --- .../Test/Mftf/Section/ProductListWidgetSection.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml new file mode 100644 index 0000000000000..4e79334a94cd3 --- /dev/null +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="ProductListWidgetSection"> + <element name="AddToCartByName" type="button" selector="//*[contains(@class,'product-item-info')][descendant::a[contains(text(), '{{arg1}}')]]//button[contains(@class,'tocart')]" parameterized="true"/> + </section> +</sections> From 95c3579b9e2b2e6c732d676155953aff3de05702 Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Mon, 29 Oct 2018 13:54:28 -0500 Subject: [PATCH 0353/1158] MAGETWO-95977: Magento 2.3.0-beta18: ReflectionException on Backend -> Stores -> Configuration -> Services -> OAuth page --- .../Integration/etc/adminhtml/system.xml | 2 +- .../System/Config/OauthSectionTest.php | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Integration/Block/Adminhtml/System/Config/OauthSectionTest.php diff --git a/app/code/Magento/Integration/etc/adminhtml/system.xml b/app/code/Magento/Integration/etc/adminhtml/system.xml index 5abec8efbfdd6..fe80fe105493a 100644 --- a/app/code/Magento/Integration/etc/adminhtml/system.xml +++ b/app/code/Magento/Integration/etc/adminhtml/system.xml @@ -54,7 +54,7 @@ <label>Maximum Login Failures to Lock Out Account</label> <comment>Maximum Number of authentication failures to lock out account.</comment> </field> - <field id="timeout" translate="label" type="text comment" sortOrder="30" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <field id="timeout" translate="label comment" type="text" sortOrder="30" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Lockout Time (seconds)</label> <comment>Period of time in seconds after which account will be unlocked.</comment> </field> diff --git a/dev/tests/integration/testsuite/Magento/Integration/Block/Adminhtml/System/Config/OauthSectionTest.php b/dev/tests/integration/testsuite/Magento/Integration/Block/Adminhtml/System/Config/OauthSectionTest.php new file mode 100644 index 0000000000000..ac5d8005180b4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Integration/Block/Adminhtml/System/Config/OauthSectionTest.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + + +namespace Magento\Integration\Block\Adminhtml\System\Config; + +class OauthSectionTest extends \Magento\TestFramework\TestCase\AbstractBackendController +{ + /** + * Checks that OAuth Section in the system config is loaded + */ + public function testOAuthSection() + { + $this->dispatch('backend/admin/system_config/edit/section/oauth/'); + $body = $this->getResponse()->getBody(); + $this->assertContains('id="oauth_access_token_lifetime-head"', $body); + $this->assertContains('id="oauth_cleanup-head"', $body); + $this->assertContains('id="oauth_consumer-head"', $body); + $this->assertContains('id="oauth_authentication_lock-head"', $body); + } +} From 774164c2ae589e45fd3bdfcf09a6de4c6b0cba1a Mon Sep 17 00:00:00 2001 From: saphal <saphal.jha@krishtechnolabs.com> Date: Tue, 30 Oct 2018 11:30:19 +0530 Subject: [PATCH 0354/1158] core modified as per instructions --- .../Magento/Review/Model/ResourceModel/Rating.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating.php b/app/code/Magento/Review/Model/ResourceModel/Rating.php index debaf61c4dd4b..df138ed8173be 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating.php @@ -34,18 +34,12 @@ class Rating extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb */ protected $_logger; - /** - * @var \Magento\Framework\App\State - */ - protected $_state; - /** * @param \Magento\Framework\Model\ResourceModel\Db\Context $context * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Module\Manager $moduleManager * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Review\Model\ResourceModel\Review\Summary $reviewSummary - * @param \Magento\Framework\App\State * @param string $connectionName */ public function __construct( @@ -54,14 +48,12 @@ public function __construct( \Magento\Framework\Module\Manager $moduleManager, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Review\Model\ResourceModel\Review\Summary $reviewSummary, - \Magento\Framework\App\State $state, $connectionName = null ) { $this->moduleManager = $moduleManager; $this->_storeManager = $storeManager; $this->_logger = $logger; $this->_reviewSummary = $reviewSummary; - $this->_state = $state; parent::__construct($context, $connectionName); } @@ -433,11 +425,11 @@ public function getReviewSummary($object, $onlyForCurrentStore = true) $data = $connection->fetchAll($select, [':review_id' => $object->getReviewId()]); - $currentStore = ($this->_state->getAreaCode() == "adminhtml") ? false : $this->_storeManager->getStore()->getId(); + $currentStore = ($this->_storeManager->isSingleStoreMode()) ? $this->_storeManager->getStore()->getId() : NULL ; if ($onlyForCurrentStore) { foreach ($data as $row) { - if ($row['store_id'] == $currentStore) { + if (!$row['store_id'] == NULL) { $object->addData($row); } } From 2ea37a87e250209d28d92b0987daddf068cfaf9c Mon Sep 17 00:00:00 2001 From: saphal <saphal.jha@krishtechnolabs.com> Date: Tue, 30 Oct 2018 12:13:38 +0530 Subject: [PATCH 0355/1158] updated code --- app/code/Magento/Review/Model/ResourceModel/Rating.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating.php b/app/code/Magento/Review/Model/ResourceModel/Rating.php index df138ed8173be..77a9727bd849e 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating.php @@ -429,7 +429,7 @@ public function getReviewSummary($object, $onlyForCurrentStore = true) if ($onlyForCurrentStore) { foreach ($data as $row) { - if (!$row['store_id'] == NULL) { + if (!$row['store_id'] == $currentStore) { $object->addData($row); } } From 3895af04b1ddfcae81717b1bf5373ded7e76c7bf Mon Sep 17 00:00:00 2001 From: Nikita Shcherbatykh <nikita.shcherbatykh@transoftgroup.com> Date: Tue, 30 Oct 2018 09:57:26 +0200 Subject: [PATCH 0356/1158] MAGETWO-95753: [2.3] Cannot save product with Tier Prices --- .../Controller/Adminhtml/ProductTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php index d949993e7ea3c..acec996d0c406 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php @@ -8,6 +8,8 @@ use Magento\Framework\App\Request\DataPersistorInterface; use Magento\Framework\Message\Manager; use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Message\MessageInterface; /** * @magentoAppArea adminhtml @@ -24,7 +26,7 @@ public function testSaveActionWithDangerRequest() $this->dispatch('backend/catalog/product/save'); $this->assertSessionMessages( $this->equalTo(['The product was unable to be saved. Please try again.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR + MessageInterface::TYPE_ERROR ); $this->assertRedirect($this->stringContains('/backend/catalog/product/new')); } @@ -44,7 +46,7 @@ public function testSaveActionAndNew() $this->assertRedirect($this->stringStartsWith('http://localhost/index.php/backend/catalog/product/new/')); $this->assertSessionMessages( $this->contains('You saved the product.'), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + MessageInterface::TYPE_SUCCESS ); } @@ -71,11 +73,11 @@ public function testSaveActionAndDuplicate() ); $this->assertSessionMessages( $this->contains('You saved the product.'), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + MessageInterface::TYPE_SUCCESS ); $this->assertSessionMessages( $this->contains('You duplicated the product.'), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + MessageInterface::TYPE_SUCCESS ); } @@ -260,9 +262,7 @@ public function saveActionWithAlreadyExistingUrlKeyDataProvider() * @param array $postData * @param array $tierPrice * @magentoDataFixture Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php - * @magentoAppIsolation enabled * @magentoConfigFixture current_store catalog/price/scope 1 - * @magentoDbIsolation disabled */ public function testSaveActionTierPrice(array $postData, array $tierPrice) { @@ -272,7 +272,7 @@ public function testSaveActionTierPrice(array $postData, array $tierPrice) $this->dispatch('backend/catalog/product/save/id/' . $postData['id']); $this->assertSessionMessages( $this->contains('You saved the product.'), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + MessageInterface::TYPE_SUCCESS ); } @@ -349,8 +349,8 @@ public function saveActionTierPriceDataProvider() */ private function getProductData(array $tierPrice) { - $repository = $this->_objectManager->create(\Magento\Catalog\Model\ProductRepository::class); - $product = $repository->get('tier_prices')->getData(); + $productRepositoryInterface = $this->_objectManager->get(ProductRepositoryInterface::class); + $product = $productRepositoryInterface->get('tier_prices')->getData(); $product['tier_price'] = $tierPrice; unset($product['entity_id']); return $product; From 42b235827941fb1713a360edcdbeebb0a95a35d4 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 30 Oct 2018 11:45:50 +0100 Subject: [PATCH 0357/1158] Consolidated cart address information provider --- .../Resolver/Address/AddressDataProvider.php | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php index d401f296cb465..80fe973c4e449 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php @@ -10,6 +10,7 @@ use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Model\Quote\Address as QuoteAddress; /** * Class AddressDataProvider @@ -49,22 +50,45 @@ public function getCartAddresses(CartInterface $cart): array if ($shippingAddress) { $shippingData = $this->dataObjectConverter->toFlatArray($shippingAddress, [], AddressInterface::class); $shippingData['address_type'] = 'SHIPPING'; - $shippingData['selected_shipping_method'] = [ - 'code' => $shippingAddress->getShippingMethod(), - 'label' => $shippingAddress->getShippingDescription(), - 'free_shipping' => $shippingAddress->getFreeShipping(), - ]; - $shippingData['items_weight'] = $shippingAddress->getWeight(); - $shippingData['customer_notes'] = $shippingAddress->getCustomerNotes(); - $addressData[] = $shippingData; + $addressData[] = array_merge($shippingData, $this->extractAddressData($shippingAddress)); } if ($billingAddress) { $billingData = $this->dataObjectConverter->toFlatArray($billingAddress, [], AddressInterface::class); $billingData['address_type'] = 'BILLING'; - $addressData[] = $billingData; + $addressData[] = array_merge($billingData, $this->extractAddressData($billingAddress)); } return $addressData; } + + /** + * Extract the necessary address fields from address model + * + * @param QuoteAddress $address + * @return array + */ + private function extractAddressData(QuoteAddress $address): array + { + $addressData = [ + 'country' => [ + 'code' => $address->getCountryId(), + 'label' => $address->getCountry() + ], + 'region' => [ + 'code' => $address->getRegionCode(), + 'label' => $address->getRegion() + ], + 'street' => $address->getStreet(), + 'selected_shipping_method' => [ + 'code' => $address->getShippingMethod(), + 'label' => $address->getShippingDescription(), + 'free_shipping' => $address->getFreeShipping(), + ], + 'items_weight' => $address->getWeight(), + 'customer_notes' => $address->getCustomerNotes() + ]; + + return $addressData; + } } From 1cfa17f2de57c9a095f248d8e9aa81e5fa3ca35b Mon Sep 17 00:00:00 2001 From: Matei Purcaru <matei.purcaru@gmail.com> Date: Tue, 30 Oct 2018 13:24:01 +0200 Subject: [PATCH 0358/1158] magento/graphql-ce#41: Updated composer.lock hash --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 1d101c8aaaf15..bc2160a2b18bd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d6640ddfd342feceaec44c406c056f57", + "content-hash": "edf8aa5e66649f1a221f027a3600d41e", "packages": [ { "name": "braintree/braintree_php", From b272c4e4bf5e3ee39ecc6376ee425f4e7ae5d27a Mon Sep 17 00:00:00 2001 From: Max Almonte <maxalmonte14@hotmail.com> Date: Tue, 30 Oct 2018 08:44:10 -0400 Subject: [PATCH 0359/1158] Removed unused properties --- .../ResourceModel/Import/Customer/Storage.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php index 38890de643295..58af2c5c1ca6e 100644 --- a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php +++ b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php @@ -44,30 +44,13 @@ class Storage protected $_byPagesIterator; /** - * @var CustomerCollectionFactory - */ - private $customerCollectionFactory; - - /** - * Customer collection. - * - * @var \Magento\Customer\Model\ResourceModel\Customer\Collection - */ - private $_customerCollection; - - /** - * @param CustomerCollectionFactory $collectionFactory * @param CollectionByPagesIteratorFactory $colIteratorFactory * @param array $data */ public function __construct( - CustomerCollectionFactory $collectionFactory, CollectionByPagesIteratorFactory $colIteratorFactory, array $data = [] ) { - $this->_customerCollection = isset( - $data['customer_collection'] - ) ? $data['customer_collection'] : $collectionFactory->create(); $this->_pageSize = isset($data['page_size']) ? $data['page_size'] : 0; $this->_byPagesIterator = isset( $data['collection_by_pages_iterator'] From 6789eb495f0ab9c8e7c532a20826e43da518f2a5 Mon Sep 17 00:00:00 2001 From: Max Almonte <maxalmonte14@hotmail.com> Date: Tue, 30 Oct 2018 09:09:04 -0400 Subject: [PATCH 0360/1158] Removed unused connection property, added PHPMD.UnusedFormalParameter directive --- .../DownloadableImportExport/Helper/Uploader.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php index 9420aeb51d41c..5fc4df1d03c49 100644 --- a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php +++ b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php @@ -38,13 +38,6 @@ class Uploader extends \Magento\Framework\App\Helper\AbstractHelper */ protected $parameters = []; - /** - * Connection resource. - * - * @var \Magento\Framework\DB\Adapter\AdapterInterface - */ - protected $connection = []; - /** * Construct * @@ -53,6 +46,8 @@ class Uploader extends \Magento\Framework\App\Helper\AbstractHelper * @param \Magento\CatalogImportExport\Model\Import\UploaderFactory $uploaderFactory * @param \Magento\Framework\App\ResourceConnection $resource * @param \Magento\Framework\Filesystem $filesystem + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( \Magento\Framework\App\Helper\Context $context, @@ -67,7 +62,6 @@ public function __construct( $this->fileUploader->init(); $this->fileUploader->setAllowedExtensions($this->getAllowedExtensions()); $this->fileUploader->removeValidateCallback('catalog_product_image'); - $this->connection = $resource->getConnection('write'); $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); } From d0c4c6411343a0dbebd2e3a2b0aa8d5be9a94ac1 Mon Sep 17 00:00:00 2001 From: Max Almonte <maxalmonte14@hotmail.com> Date: Tue, 30 Oct 2018 09:14:07 -0400 Subject: [PATCH 0361/1158] Fixed property type in docblock --- .../Magento/CustomerImportExport/Model/Import/Address.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php index 9ba50738ebc1a..a8ca6969a6ea1 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php @@ -104,9 +104,9 @@ class Address extends AbstractCustomer /** * Region collection instance * - * @var string + * @var \Magento\Directory\Model\ResourceModel\Region\Collection */ - protected $_regionCollection; + private $_regionCollection; /** * Countries and regions From e9730955a3029c4f75f0a80bad31e9f2cc2480cd Mon Sep 17 00:00:00 2001 From: Max Almonte <maxalmonte14@hotmail.com> Date: Tue, 30 Oct 2018 09:21:07 -0400 Subject: [PATCH 0362/1158] Added back customerCollectionFactory property --- .../Model/ResourceModel/Import/Customer/Storage.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php index 58af2c5c1ca6e..c5d28240c3068 100644 --- a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php +++ b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php @@ -44,10 +44,17 @@ class Storage protected $_byPagesIterator; /** + * @var CustomerCollectionFactory + */ + private $customerCollectionFactory; + + /** + * @param CustomerCollectionFactory $collectionFactory * @param CollectionByPagesIteratorFactory $colIteratorFactory * @param array $data */ public function __construct( + CustomerCollectionFactory $collectionFactory, CollectionByPagesIteratorFactory $colIteratorFactory, array $data = [] ) { From 1e304992e950945394ea331004fe700b6173a909 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 30 Oct 2018 15:46:55 +0200 Subject: [PATCH 0363/1158] MAGETWO-94835: Automate with MFTF Filter shared catalogs by 'Created By' field --- .../Mftf/Section/CheckoutShippingSection.xml | 1 + .../AdminDeleteUserActionGroup.xml | 28 +++++++++++++++++++ .../Magento/User/Test/Mftf/Data/UserData.xml | 14 ++++++++++ .../User/Test/Mftf/Metadata/user-meta.xml | 5 +++- 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserActionGroup.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml index ff7f8995c0681..fb9a79bc93865 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml @@ -33,5 +33,6 @@ <element name="defaultShipping" type="button" selector=".billing-address-details"/> <element name="state" type="button" selector="//*[text()='Alabama']"/> <element name="stateInput" type="input" selector="input[name=region]"/> + <element name="editActiveAddress" type="button" selector="//div[@class='shipping-address-item selected-item']//span[text()='Edit']" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserActionGroup.xml new file mode 100644 index 0000000000000..70c0a772ec341 --- /dev/null +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserActionGroup.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCustomUserActionGroup"> + <arguments> + <argument name="user"/> + </arguments> + <amOnPage url="{{AdminUsersPage.url}}" stepKey="navigateToUserGrid" /> + <fillField selector="{{AdminUserGridSection.usernameFilterTextField}}" userInput="{{user.username}}" stepKey="enterUserName" /> + <click selector="{{AdminUserGridSection.searchButton}}" stepKey="clickSearch" /> + <waitForPageLoad stepKey="waitForGridToLoad"/> + <see selector="{{AdminUserGridSection.usernameInFirstRow}}" userInput="{{user.username}}" stepKey="seeUser" /> + <click selector="{{AdminUserGridSection.searchResultFirstRow}}" stepKey="openUserEdit"/> + <waitForPageLoad stepKey="waitForUserEditPageLoad"/> + <fillField selector="{{AdminEditUserSection.currentPasswordField}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}" stepKey="enterThePassword" /> + <click selector="{{AdminMainActionsSection.delete}}" stepKey="deleteUser"/> + <waitForElementVisible selector="{{AdminConfirmationModalSection.message}}" stepKey="waitForConfirmModal"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDelete"/> + <waitForPageLoad stepKey="waitForSave" /> + <see selector="{{AdminMessagesSection.success}}" userInput="You deleted the user." stepKey="seeUserDeleteMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/User/Test/Mftf/Data/UserData.xml b/app/code/Magento/User/Test/Mftf/Data/UserData.xml index 03ae3dba21840..80c1cc3022964 100644 --- a/app/code/Magento/User/Test/Mftf/Data/UserData.xml +++ b/app/code/Magento/User/Test/Mftf/Data/UserData.xml @@ -18,4 +18,18 @@ <data key="lastName">Smith</data> <data key="password">admin123</data> </entity> + <entity name="Admin3" type="user"> + <data key="username" unique="suffix">admin3</data> + <data key="firstname">admin3</data> + <data key="lastname">admin3</data> + <data key="email" unique="prefix">admin3WebUser@example.com</data> + <data key="password">123123q</data> + <data key="password_confirmation">123123q</data> + <data key="interface_local">en_US</data> + <data key="is_active">true</data> + <data key="current_password">123123q</data> + <array key="roles"> + <item>1</item> + </array> + </entity> </entities> diff --git a/app/code/Magento/User/Test/Mftf/Metadata/user-meta.xml b/app/code/Magento/User/Test/Mftf/Metadata/user-meta.xml index 2e1e5f6f5a97d..1ee29be6b3d76 100644 --- a/app/code/Magento/User/Test/Mftf/Metadata/user-meta.xml +++ b/app/code/Magento/User/Test/Mftf/Metadata/user-meta.xml @@ -6,7 +6,7 @@ */ --> <operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> <operation name="CreateUser" dataType="user" type="create" auth="adminFormKey" url="/admin/user/save/" method="POST" successRegex="/messages-message-success/" returnRegex="" > <contentType>application/x-www-form-urlencoded</contentType> @@ -19,5 +19,8 @@ <field key="interface_locale">string</field> <field key="is_active">boolean</field> <field key="current_password">string</field> + <array key="roles"> + <value>string</value> + </array> </operation> </operations> From 152b0924d652de96bb49a93959bb3b304e2601ba Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Tue, 30 Oct 2018 16:34:52 +0200 Subject: [PATCH 0364/1158] Fix Notice and Exception while adding image to product programmatically --- .../Model/Product/Gallery/Processor.php | 24 +++++++++++++++---- composer.json | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index c6c7fbda7e9ec..225c502830695 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -6,6 +6,7 @@ namespace Magento\Catalog\Model\Product\Gallery; +use Magento\Framework\Api\Data\ImageContentInterface; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem\DriverInterface; @@ -183,6 +184,13 @@ public function addImage( $attrCode = $this->getAttribute()->getAttributeCode(); $mediaGalleryData = $product->getData($attrCode); $position = 0; + + $absoluteFilePath = $this->mediaDirectory->getAbsolutePath($file); + $imageMimeType = mime_content_type($absoluteFilePath); + $imageContent = file_get_contents($absoluteFilePath); + $imageBase64 = base64_encode($imageContent); + $imageName = pathinfo($destinationFile, PATHINFO_FILENAME); + if (!is_array($mediaGalleryData)) { $mediaGalleryData = ['images' => []]; } @@ -195,11 +203,19 @@ public function addImage( $position++; $mediaGalleryData['images'][] = [ - 'file' => $fileName, - 'position' => $position, + 'file' => $fileName, + 'position' => $position, + 'label' => '', + 'disabled' => (int)$exclude, 'media_type' => 'image', - 'label' => '', - 'disabled' => (int)$exclude, + 'types' => $mediaAttribute, + 'content' => [ + 'data' => [ + ImageContentInterface::NAME => $imageName, + ImageContentInterface::BASE64_ENCODED_DATA => $imageBase64, + ImageContentInterface::TYPE => $imageMimeType, + ] + ] ]; $product->setData($attrCode, $mediaGalleryData); diff --git a/composer.json b/composer.json index e2a646275d98b..68bf1f1d8a8b0 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "ext-xsl": "*", "ext-zip": "*", "lib-libxml": "*", + "ext-fileinfo": "*", "braintree/braintree_php": "3.35.0", "colinmollenhour/cache-backend-file": "~1.4.1", "colinmollenhour/cache-backend-redis": "1.10.5", From 898d2a507a283c15af63dedf2c837bbba03ba89c Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Tue, 30 Oct 2018 17:52:51 +0300 Subject: [PATCH 0365/1158] MAGETWO-91650: Translation not working for product alerts - Replacing name with referenceId --- app/code/Magento/ProductAlert/etc/db_schema.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ProductAlert/etc/db_schema.xml b/app/code/Magento/ProductAlert/etc/db_schema.xml index c6dd8db321b54..820a8029e2d95 100644 --- a/app/code/Magento/ProductAlert/etc/db_schema.xml +++ b/app/code/Magento/ProductAlert/etc/db_schema.xml @@ -52,7 +52,7 @@ <index referenceId="PRODUCT_ALERT_PRICE_WEBSITE_ID" indexType="btree"> <column name="website_id"/> </index> - <index name="PRODUCT_ALERT_PRICE_STORE_ID" indexType="btree"> + <index referenceId="PRODUCT_ALERT_PRICE_STORE_ID" indexType="btree"> <column name="store_id"/> </index> </table> @@ -99,7 +99,7 @@ <index referenceId="PRODUCT_ALERT_STOCK_WEBSITE_ID" indexType="btree"> <column name="website_id"/> </index> - <index name="PRODUCT_ALERT_STOCK_STORE_ID" indexType="btree"> + <index referenceId="PRODUCT_ALERT_STOCK_STORE_ID" indexType="btree"> <column name="store_id"/> </index> </table> From fab32c6f68410e507b721206a8902ea77d1ce506 Mon Sep 17 00:00:00 2001 From: David Manners <dmanners87@gmail.com> Date: Tue, 30 Oct 2018 15:32:35 +0000 Subject: [PATCH 0366/1158] Fix PHPCS check for "Short description must start with a capital letter" --- .../Magento/CustomerImportExport/Model/Import/Address.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php index a8ca6969a6ea1..7a1a09efaa7b6 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php @@ -788,7 +788,7 @@ public static function getDefaultAddressAttributeMapping() } /** - * check if address for import is empty (for customer composite mode) + * Check if address for import is empty (for customer composite mode) * * @param array $rowData * @return array @@ -947,7 +947,7 @@ protected function _checkRowDuplicate($customerId, $addressId) } /** - * set customer attributes + * Set customer attributes * * @param array $customerAttributes * @return $this From 63d8818f8ed7ae112cb758e15f1ca967c10ca9f2 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Tue, 30 Oct 2018 18:25:45 +0200 Subject: [PATCH 0367/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Remove redundant js files; - Refactored customer and customer address data providers; --- .../Address/AbstractDefaultAddress.php | 2 +- .../Controller/Adminhtml/Address/Delete.php | 2 +- .../Adminhtml/Address/MassDelete.php | 6 +- .../Controller/Adminhtml/Address/Save.php | 2 +- .../Controller/Adminhtml/Address/Validate.php | 6 +- .../Customer/Model/Address/DataProvider.php | 411 ++---------------- .../Model/AttributeMetadataResolver.php | 238 ++++++++++ .../DataProviderWithDefaultAddresses.php | 398 ++--------------- .../Model/FileUploaderDataResolver.php | 201 +++++++++ .../ui_component/customer_address_form.xml | 4 +- .../web/js/address/default-address-block.js | 17 - .../view/adminhtml/web/js/address/modal.js | 203 --------- .../web/js/form/components/insert-form.js | 164 ------- .../view/base/ui_component/customer_form.xml | 9 +- .../base/web/js/form/components/collection.js | 4 - .../web/js/form/components/collection/item.js | 3 - .../Test/Php/_files/blacklist/strict_type.txt | 2 +- .../config/customerConfig.xml | 2 +- 18 files changed, 524 insertions(+), 1150 deletions(-) create mode 100644 app/code/Magento/Customer/Model/AttributeMetadataResolver.php create mode 100644 app/code/Magento/Customer/Model/FileUploaderDataResolver.php delete mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js delete mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js delete mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index a2f9d12282188..75b888bb06675 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -49,7 +49,7 @@ public function __construct( } /** - * Execute action to change customer default address + * Execute action to set customer default billing or shipping address * * @return \Magento\Framework\Controller\Result\Redirect */ diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 8443c777546f6..1620f343700ed 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -40,7 +40,7 @@ public function __construct( } /** - * Delete action + * Delete customer address action * * @return \Magento\Framework\Controller\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index f022ea36f420d..2ea4b79f78028 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -9,7 +9,6 @@ use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; -use Magento\Backend\Model\View\Result\Redirect; use Magento\Customer\Api\AddressRepositoryInterface; /** @@ -58,7 +57,7 @@ public function __construct( } /** - * Execute action + * Delete specified customer addresses using grid massaction * * @return \Magento\Backend\Model\View\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException|\Exception @@ -69,8 +68,7 @@ public function execute() $collection = $this->filter->getCollection($this->collectionFactory->create()); $collectionSize = $collection->getSize(); - // Get id of the first item from addresses collection for providing it to the ResultRedirect and build a - // proper redirect URL + // Get id of the first item from addresses collection for the ResultRedirect and build a correct redirect URL $customerId = $collection->getFirstItem()->getParentId(); /** @var \Magento\Customer\Model\Address $address */ diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index e1d605a8d0890..9113640112e3b 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -79,7 +79,7 @@ public function __construct( } /** - * Execute action to save customer address + * Save customer address action * * @return \Magento\Framework\Controller\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php index 696bf3099db11..e4583230d5294 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -48,7 +48,7 @@ public function __construct( } /** - * AJAX customer validation action + * AJAX customer address validation action * * @return \Magento\Framework\Controller\Result\Json */ @@ -56,7 +56,7 @@ public function execute() { /** @var \Magento\Framework\DataObject $response */ $response = new \Magento\Framework\DataObject(); - $response->setError(0); + $response->setError(false); /** @var \Magento\Framework\DataObject $validatedResponse */ $validatedResponse = $this->validateCustomerAddress($response); @@ -89,7 +89,7 @@ private function validateCustomerAddress(\Magento\Framework\DataObject $response $messages[] = $error; } $response->setMessages($messages); - $response->setError(1); + $response->setError(true); } return $response; diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 7f23deddd89a6..5fd7c884cf6b5 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -1,9 +1,9 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Customer\Model\Address; use Magento\Customer\Api\CustomerRepositoryInterface; @@ -11,38 +11,17 @@ use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Type; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Customer\Api\Data\AddressInterface; -use Magento\Ui\DataProvider\EavValidationRules; -use Magento\Ui\Component\Form\Field; -use Magento\Eav\Api\Data\AttributeInterface; -use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; -use Magento\Customer\Model\Attribute; -use Magento\Framework\App\ObjectManager; -use Magento\Customer\Api\Data\CustomerInterface; -use Magento\Customer\Api\AddressMetadataInterface; -use Magento\Customer\Api\CustomerMetadataInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Customer\Model\Address; -use Magento\Customer\Model\FileProcessor; -use Magento\Customer\Model\FileProcessorFactory; +use Magento\Customer\Model\FileUploaderDataResolver; +use Magento\Customer\Model\AttributeMetadataResolver; /** - * Dataprovider for customer address grid. - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * Dataprovider of customer addresses for customer address grid. + * @property \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider { - /** - * Maximum file size allowed for file_uploader UI component - */ - const MAX_FILE_SIZE = 2097152; - - /** - * @var \Magento\Customer\Model\ResourceModel\Address\Collection - */ - protected $collection; - /** * @var CustomerRepositoryInterface */ @@ -53,42 +32,6 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $loadedData; - /** - * EAV attribute properties to fetch from meta storage - * @var array - */ - private $metaProperties = [ - 'dataType' => 'frontend_input', - 'visible' => 'is_visible', - 'required' => 'is_required', - 'label' => 'frontend_label', - 'sortOrder' => 'sort_order', - 'notice' => 'note', - 'default' => 'default_value', - 'size' => 'multiline_count', - ]; - - /** - * Form element mapping - * - * @var array - */ - private $formElement = [ - 'text' => 'input', - 'hidden' => 'input', - 'boolean' => 'checkbox', - ]; - - /** - * @var EavValidationRules - */ - private $eavValidationRules; - - /** - * @var CountryWithWebsites - */ - private $countryWithWebsiteSource; - /** * Allow to manage attributes, even they are hidden on storefront * @@ -101,26 +44,6 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $context; - /** - * File types allowed for file_uploader UI component - * - * @var array - */ - private $fileUploaderTypes = [ - 'image', - 'file', - ]; - - /** - * @var \Magento\Customer\Model\Config\Share - */ - private $shareConfig; - - /** - * @var FileProcessorFactory - */ - private $fileProcessorFactory; - /** * @var array */ @@ -129,7 +52,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider /** * @var array */ - private $attributesToEliminate = [ + private static $attributesToEliminate = [ 'region', 'vat_is_valid', 'vat_request_date', @@ -137,6 +60,16 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider 'vat_request_success' ]; + /** + * @var FileUploaderDataResolver + */ + private $fileUploaderDataResolver; + + /** + * @var AttributeMetadataResolver + */ + private $attributeMetadataResolver; + /** * DataProvider constructor. * @param string $name @@ -145,11 +78,9 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param CollectionFactory $addressCollectionFactory * @param CustomerRepositoryInterface $customerRepository * @param Config $eavConfig - * @param EavValidationRules $eavValidationRules * @param ContextInterface $context - * @param FileProcessorFactory $fileProcessorFactory - * @param \Magento\Customer\Model\Config\Share $shareConfig - * @param CountryWithWebsites $countryWithWebsites + * @param FileUploaderDataResolver $fileUploaderDataResolver + * @param AttributeMetadataResolver $attributeMetadataResolver * @param array $meta * @param array $data * @param bool $allowToShowHiddenAttributes @@ -162,11 +93,9 @@ public function __construct( CollectionFactory $addressCollectionFactory, CustomerRepositoryInterface $customerRepository, Config $eavConfig, - EavValidationRules $eavValidationRules, ContextInterface $context, - FileProcessorFactory $fileProcessorFactory, - \Magento\Customer\Model\Config\Share $shareConfig, - CountryWithWebsites $countryWithWebsites, + FileUploaderDataResolver $fileUploaderDataResolver, + AttributeMetadataResolver $attributeMetadataResolver, array $meta = [], array $data = [], $allowToShowHiddenAttributes = true @@ -175,12 +104,10 @@ public function __construct( $this->collection = $addressCollectionFactory->create(); $this->collection->addAttributeToSelect('*'); $this->customerRepository = $customerRepository; - $this->eavValidationRules = $eavValidationRules; $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; $this->context = $context; - $this->fileProcessorFactory = $fileProcessorFactory; - $this->countryWithWebsiteSource = $countryWithWebsites; - $this->shareConfig = $shareConfig; + $this->fileUploaderDataResolver = $fileUploaderDataResolver; + $this->attributeMetadataResolver = $attributeMetadataResolver; $this->meta['general']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer_address') ); @@ -193,7 +120,7 @@ public function __construct( * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function getData() + public function getData(): array { if (null !== $this->loadedData) { return $this->loadedData; @@ -210,7 +137,8 @@ public function getData() $defaultBilling = $customer->getDefaultBilling(); $defaultShipping = $customer->getDefaultShipping(); $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); - $this->overrideFileUploaderData($item, $this->loadedData[$addressId]); + + $this->fileUploaderDataResolver->overrideFileUploaderData($item, $this->loadedData[$addressId]); } if (null === $this->loadedData) { @@ -229,15 +157,15 @@ public function getData() * @param string|null $defaultShipping * @return void */ - private function prepareAddressData($addressId, array &$addresses, $defaultBilling, $defaultShipping) + private function prepareAddressData($addressId, array &$addresses, $defaultBilling, $defaultShipping): void { - if (null !== $defaultBilling && $addressId == $defaultBilling) { + if (null !== $defaultBilling && $addressId === $defaultBilling) { $addresses[$addressId]['default_billing'] = '1'; } - if (null !== $defaultShipping && $addressId == $defaultShipping) { + if (null !== $defaultShipping && $addressId === $defaultShipping) { $addresses[$addressId]['default_shipping'] = '1'; } - if (null !== $addresses[$addressId]['street'] && !is_array($addresses[$addressId]['street'])) { + if (null !== $addresses[$addressId]['street'] && !\is_array($addresses[$addressId]['street'])) { $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); } } @@ -249,7 +177,7 @@ private function prepareAddressData($addressId, array &$addresses, $defaultBilli * @throws \Magento\Framework\Exception\NoSuchEntityException * @return array */ - private function getDefaultData() + private function getDefaultData(): array { $parentId = $this->context->getRequestParam('parent_id'); $customer = $this->customerRepository->getById($parentId); @@ -262,30 +190,6 @@ private function getDefaultData() return $data; } - /** - * Override file uploader UI component data - * - * Overrides data for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Address $entity - * @param array $entityData - * @return void - */ - private function overrideFileUploaderData($entity, array &$entityData) - { - $attributes = $entity->getAttributes(); - foreach ($attributes as $attribute) { - /** @var Attribute $attribute */ - if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( - $entity->getEntityType(), - $attribute, - $entityData - ); - } - } - } - /** * Get attributes meta * @@ -299,259 +203,22 @@ protected function getAttributesMeta(Type $entityType): array $attributes = $entityType->getAttributeCollection(); /* @var AbstractAttribute $attribute */ foreach ($attributes as $attribute) { - $this->processFrontendInput($attribute, $meta); - - $code = $attribute->getAttributeCode(); - - if (in_array($attribute->getFrontendInput(), $this->bannedInputTypes)) { + if (\in_array($attribute->getFrontendInput(), $this->bannedInputTypes, true)) { continue; } - if (in_array($attribute->getAttributeCode(), $this->attributesToEliminate)) { + if (\in_array($attribute->getAttributeCode(), self::$attributesToEliminate, true)) { continue; } - // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value - foreach ($this->metaProperties as $metaName => $origName) { - $value = $attribute->getDataUsingMethod($origName); - $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; - if ('frontend_input' === $origName) { - $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; - } - } - - if ($attribute->usesSource()) { - if ($code == AddressInterface::COUNTRY_ID) { - $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource - ->getAllOptions(); - } else { - $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); - } - } - - $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); - if (!empty($rules)) { - $meta[$code]['arguments']['data']['config']['validation'] = $rules; - } - - $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; - $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); - - $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + $meta[$attribute->getAttributeCode()] = $this->attributeMetadataResolver->getAttributesMeta( + $attribute, + $entityType, + $this->allowToShowHiddenAttributes, + $this->getRequestFieldName() + ); } + $this->attributeMetadataResolver->processWebsiteMeta($meta); - $this->processWebsiteMeta($meta); return $meta; } - - /** - * Process attributes by frontend input type - * - * @param AttributeInterface $attribute - * @param array $meta - * @return void - */ - private function processFrontendInput(AttributeInterface $attribute, array &$meta) - { - $code = $attribute->getAttributeCode(); - if ($attribute->getFrontendInput() === 'boolean') { - $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; - $meta[$code]['arguments']['data']['config']['valueMap'] = [ - 'true' => '1', - 'false' => '0', - ]; - } - } - - /** - * Detect can we show attribute on specific form or not - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttribute(AbstractAttribute $customerAttribute): bool - { - $userDefined = (bool) $customerAttribute->getIsUserDefined(); - if (!$userDefined) { - return $customerAttribute->getIsVisible(); - } - - $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); - - return ($this->allowToShowHiddenAttributes && $canShowOnForm) || - (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); - } - - /** - * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttributeInForm(AbstractAttribute $customerAttribute): bool - { - $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; - - if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { - return is_array($customerAttribute->getUsedInForms()) && - ( - (in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || - (in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) - ); - } - return is_array($customerAttribute->getUsedInForms()) && - in_array('customer_address_edit', $customerAttribute->getUsedInForms()); - } - - /** - * Override file uploader UI component metadata - * - * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Type $entityType - * @param AbstractAttribute $attribute - * @param array $config - * @return void - */ - private function overrideFileUploaderMetadata( - Type $entityType, - AbstractAttribute $attribute, - array &$config - ) { - if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $maxFileSize = self::MAX_FILE_SIZE; - - if (isset($config['validation']['max_file_size'])) { - $maxFileSize = (int)$config['validation']['max_file_size']; - } - - $allowedExtensions = []; - - if (isset($config['validation']['file_extensions'])) { - $allowedExtensions = explode(',', $config['validation']['file_extensions']); - array_walk($allowedExtensions, function (&$value) { - $value = strtolower(trim($value)); - }); - } - - $allowedExtensions = implode(' ', $allowedExtensions); - - $entityTypeCode = $entityType->getEntityTypeCode(); - $url = $this->getFileUploadUrl($entityTypeCode); - - $config = [ - 'formElement' => 'fileUploader', - 'componentType' => 'fileUploader', - 'maxFileSize' => $maxFileSize, - 'allowedExtensions' => $allowedExtensions, - 'uploaderConfig' => [ - 'url' => $url, - ], - 'label' => $this->getMetadataValue($config, 'label'), - 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), - 'required' => $this->getMetadataValue($config, 'required'), - 'visible' => $this->getMetadataValue($config, 'visible'), - 'validation' => $this->getMetadataValue($config, 'validation'), - ]; - } - } - - /** - * Add global scope parameter and filter options to website meta - * - * @param array $meta - * @return void - */ - private function processWebsiteMeta(&$meta) - { - if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { - $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; - } - - if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { - $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ - 'target' => 'customer_form.customer_form_data_source:data.customer.website_id', - 'field' => 'website_ids' - ]; - } - } - - /** - * Retrieve metadata value - * - * @param array $config - * @param string $name - * @param mixed $default - * @return mixed - */ - private function getMetadataValue($config, $name, $default = null) - { - return $config[$name] ?? $default; - } - - /** - * Retrieve URL to file upload - * - * @param string $entityTypeCode - * @return string - */ - private function getFileUploadUrl($entityTypeCode): string - { - switch ($entityTypeCode) { - case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: - $url = 'customer/file/customer_upload'; - break; - - case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: - $url = 'customer/file/address_upload'; - break; - - default: - $url = ''; - break; - } - return $url; - } - - /** - * Retrieve array of values required by file uploader UI component - * - * @param Type $entityType - * @param Attribute $attribute - * @param array $customerData - * @return array - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function getFileUploaderData( - Type $entityType, - Attribute $attribute, - array $customerData - ): array { - $attributeCode = $attribute->getAttributeCode(); - - $file = $customerData[$attributeCode] ?? ''; - - /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->fileProcessorFactory->create([ - 'entityTypeCode' => $entityType->getEntityTypeCode(), - ]); - - if (!empty($file) - && $fileProcessor->isExist($file) - ) { - $stat = $fileProcessor->getStat($file); - $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); - - return [ - [ - 'file' => $file, - 'size' => null !== $stat ? $stat['size'] : 0, - 'url' => $viewUrl ?? '', - 'name' => basename($file), - 'type' => $fileProcessor->getMimeType($file), - ], - ]; - } - - return []; - } } diff --git a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php new file mode 100644 index 0000000000000..36ffcb2f5495b --- /dev/null +++ b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php @@ -0,0 +1,238 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model; + +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Ui\Component\Form\Field; +use Magento\Eav\Model\Entity\Type; +use Magento\Eav\Api\Data\AttributeInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Config\Share as ShareConfig; + +/** + * Class to build meta data of the customer or customer address attribute + */ +class AttributeMetadataResolver +{ + /** + * EAV attribute properties to fetch from meta storage + * @var array + */ + private static $metaProperties = [ + 'dataType' => 'frontend_input', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ]; + + /** + * Form element mapping + * + * @var array + */ + private static $formElement = [ + 'text' => 'input', + 'hidden' => 'input', + 'boolean' => 'checkbox', + ]; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsiteSource; + + /** + * @var EavValidationRules + */ + private $eavValidationRules; + + /** + * @var FileUploaderDataResolver + */ + private $fileUploaderDataResolver; + + /** + * @var ContextInterface + */ + private $context; + + /** + * @var ShareConfig + */ + private $shareConfig; + + /** + * @param CountryWithWebsites $countryWithWebsiteSource + * @param EavValidationRules $eavValidationRules + * @param \Magento\Customer\Model\FileUploaderDataResolver $fileUploaderDataResolver + * @param ContextInterface $context + * @param ShareConfig $shareConfig + */ + public function __construct( + CountryWithWebsites $countryWithWebsiteSource, + EavValidationRules $eavValidationRules, + fileUploaderDataResolver $fileUploaderDataResolver, + ContextInterface $context, + ShareConfig $shareConfig + ) { + $this->countryWithWebsiteSource = $countryWithWebsiteSource; + $this->eavValidationRules = $eavValidationRules; + $this->fileUploaderDataResolver = $fileUploaderDataResolver; + $this->context = $context; + $this->shareConfig = $shareConfig; + } + + /** + * Get meta data of the customer or customer address attribute + * + * @param AbstractAttribute $attribute + * @param Type $entityType + * @param bool $allowToShowHiddenAttributes + * @param string $requestFieldName + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getAttributesMeta( + AbstractAttribute $attribute, + Type $entityType, + bool $allowToShowHiddenAttributes, + string $requestFieldName + ): array { + $meta = $this->modifyBooleanAttributeMeta($attribute); + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value + foreach (self::$metaProperties as $metaName => $origName) { + $value = $attribute->getDataUsingMethod($origName); + $meta['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; + if ('frontend_input' === $origName) { + $meta['arguments']['data']['config']['formElement'] = self::$formElement[$value] ?? $value; + } + } + + if ($attribute->usesSource()) { + if ($attribute->getAttributeCode() === AddressInterface::COUNTRY_ID) { + $meta['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource + ->getAllOptions(); + } else { + $meta['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } + } + + $rules = $this->eavValidationRules->build($attribute, $meta['arguments']['data']['config']); + if (!empty($rules)) { + $meta['arguments']['data']['config']['validation'] = $rules; + } + + $meta['arguments']['data']['config']['componentType'] = Field::NAME; + $meta['arguments']['data']['config']['visible'] = $this->canShowAttribute( + $attribute, + $requestFieldName, + $allowToShowHiddenAttributes + ); + + $this->fileUploaderDataResolver->overrideFileUploaderMetadata( + $entityType, + $attribute, + $meta['arguments']['data']['config'] + ); + + return $meta; + } + + /** + * Detect can we show attribute on specific form or not + * + * @param AbstractAttribute $customerAttribute + * @param string $requestFieldName + * @param bool $allowToShowHiddenAttributes + * @return bool + */ + private function canShowAttribute( + AbstractAttribute $customerAttribute, + string $requestFieldName, + bool $allowToShowHiddenAttributes + ) { + $userDefined = (bool)$customerAttribute->getIsUserDefined(); + if (!$userDefined) { + return $customerAttribute->getIsVisible(); + } + + $canShowOnForm = $this->canShowAttributeInForm($customerAttribute, $requestFieldName); + + return ($allowToShowHiddenAttributes && $canShowOnForm) || + (!$allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); + } + + /** + * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... + * + * @param AbstractAttribute $customerAttribute + * @param string $requestFieldName + * @return bool + */ + private function canShowAttributeInForm(AbstractAttribute $customerAttribute, string $requestFieldName): bool + { + $isRegistration = $this->context->getRequestParam($requestFieldName) === null; + + if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { + return \is_array($customerAttribute->getUsedInForms()) && + ( + (\in_array('customer_account_create', $customerAttribute->getUsedInForms(), true) && $isRegistration) || + (\in_array('customer_account_edit', $customerAttribute->getUsedInForms(), true) && !$isRegistration) + ); + } + return \is_array($customerAttribute->getUsedInForms()) && + \in_array('customer_address_edit', $customerAttribute->getUsedInForms(), true); + } + + /** + * Modify boolean attribute meta data + * + * @param AttributeInterface $attribute + * @return array + */ + private function modifyBooleanAttributeMeta(AttributeInterface $attribute): array + { + $meta = []; + if ($attribute->getFrontendInput() === 'boolean') { + $meta['arguments']['data']['config']['prefer'] = 'toggle'; + $meta['arguments']['data']['config']['valueMap'] = [ + 'true' => '1', + 'false' => '0', + ]; + } + + return $meta; + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + public function processWebsiteMeta(&$meta): void + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => 'customer_form.customer_form_data_source:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } +} diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 7ba6484dc3f2b..9131fb2ccdce2 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -6,112 +6,37 @@ */ namespace Magento\Customer\Model\Customer; -use Magento\Customer\Api\AddressMetadataInterface; -use Magento\Customer\Api\CustomerMetadataInterface; -use Magento\Customer\Api\Data\AddressInterface; -use Magento\Customer\Api\Data\CustomerInterface; use Magento\Customer\Model\Address; -use Magento\Customer\Model\Attribute; use Magento\Customer\Model\Customer; -use Magento\Customer\Model\FileProcessor; -use Magento\Customer\Model\FileProcessorFactory; -use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory; -use Magento\Eav\Api\Data\AttributeInterface; use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Eav\Model\Entity\Type; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Session\SessionManagerInterface; -use Magento\Framework\View\Element\UiComponent\ContextInterface; -use Magento\Ui\Component\Form\Field; -use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Customer\Model\FileUploaderDataResolver; +use Magento\Customer\Model\AttributeMetadataResolver; /** * Refactored version of Magento\Customer\Model\Customer\DataProvider with eliminated usage of addresses collection. - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\AbstractDataProvider { - /** - * Maximum file size allowed for file_uploader UI component - */ - const MAX_FILE_SIZE = 2097152; - /** * @var array */ private $loadedData; - /** - * @var CountryWithWebsites - */ - private $countryWithWebsiteSource; - - /** - * @var \Magento\Customer\Model\Config\Share - */ - private $shareConfig; - - /** - * EAV attribute properties to fetch from meta storage - * @var array - */ - private $metaProperties = [ - 'dataType' => 'frontend_input', - 'visible' => 'is_visible', - 'required' => 'is_required', - 'label' => 'frontend_label', - 'sortOrder' => 'sort_order', - 'notice' => 'note', - 'default' => 'default_value', - 'size' => 'multiline_count', - ]; - - /** - * Form element mapping - * - * @var array - */ - private $formElement = [ - 'text' => 'input', - 'hidden' => 'input', - 'boolean' => 'checkbox', - ]; - - /** - * @var EavValidationRules - */ - private $eavValidationRules; - /** * @var SessionManagerInterface - * @since 100.1.0 */ private $session; - /** - * @var FileProcessorFactory - */ - private $fileProcessorFactory; - - /** - * File types allowed for file_uploader UI component - * - * @var array - */ - private $fileUploaderTypes = [ - 'image', - 'file', - ]; - /** * Customer fields that must be removed * * @var array */ - private $forbiddenCustomerFields = [ + private static $forbiddenCustomerFields = [ 'password_hash', 'rp_token', 'confirmation', @@ -135,54 +60,52 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract private $countryFactory; /** - * DataProviderWithDefaultAddresses constructor. - * + * @var FileUploaderDataResolver + */ + private $fileUploaderDataResolver; + + /** + * @var AttributeMetadataResolver + */ + private $attributeMetadataResolver; + + /** * @param string $name * @param string $primaryFieldName * @param string $requestFieldName - * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig - * @param FileProcessorFactory $fileProcessorFactory - * @param ContextInterface $context * @param \Magento\Directory\Model\CountryFactory $countryFactory * @param SessionManagerInterface $session - * @param \Magento\Customer\Model\Config\Share $shareConfig - * @param CountryWithWebsites $countryWithWebsites + * @param FileUploaderDataResolver $fileUploaderDataResolver + * @param AttributeMetadataResolver $attributeMetadataResolver * @param bool $allowToShowHiddenAttributes * @param array $meta * @param array $data - * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @throws \Magento\Framework\Exception\LocalizedException */ public function __construct( string $name, string $primaryFieldName, string $requestFieldName, - EavValidationRules $eavValidationRules, CustomerCollectionFactory $customerCollectionFactory, Config $eavConfig, - FileProcessorFactory $fileProcessorFactory, - ContextInterface $context, \Magento\Directory\Model\CountryFactory $countryFactory, - \Magento\Framework\Session\SessionManagerInterface $session, - \Magento\Customer\Model\Config\Share $shareConfig, - CountryWithWebsites $countryWithWebsites, + SessionManagerInterface $session, + FileUploaderDataResolver $fileUploaderDataResolver, + AttributeMetadataResolver $attributeMetadataResolver, $allowToShowHiddenAttributes = true, array $meta = [], array $data = [] ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); - $this->eavValidationRules = $eavValidationRules; $this->collection = $customerCollectionFactory->create(); $this->collection->addAttributeToSelect('*'); - $this->fileProcessorFactory = $fileProcessorFactory; - $this->context = $context ?: ObjectManager::getInstance()->get(ContextInterface::class); $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; $this->session = $session; - $this->countryWithWebsiteSource = $countryWithWebsites; - $this->shareConfig = $shareConfig; $this->countryFactory = $countryFactory; + $this->fileUploaderDataResolver = $fileUploaderDataResolver; + $this->attributeMetadataResolver = $attributeMetadataResolver; $this->meta['customer']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer') ); @@ -193,7 +116,7 @@ public function __construct( * * @return array */ - public function getData() + public function getData(): array { if (null !== $this->loadedData) { return $this->loadedData; @@ -203,11 +126,11 @@ public function getData() foreach ($items as $customer) { $result['customer'] = $customer->getData(); - $this->overrideFileUploaderData($customer, $result['customer']); + $this->fileUploaderDataResolver->overrideFileUploaderData($customer, $result['customer']); $result['customer'] = array_diff_key( $result['customer'], - array_flip($this->forbiddenCustomerFields) + array_flip(self::$forbiddenCustomerFields) ); unset($result['address']); @@ -254,73 +177,6 @@ private function prepareDefaultAddress($address): array return $addressData; } - /** - * Override file uploader UI component data - * - * Overrides data for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Customer|Address $entity - * @param array $entityData - * @return void - */ - private function overrideFileUploaderData($entity, array &$entityData) - { - $attributes = $entity->getAttributes(); - foreach ($attributes as $attribute) { - /** @var Attribute $attribute */ - if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( - $entity->getEntityType(), - $attribute, - $entityData - ); - } - } - } - - /** - * Retrieve array of values required by file uploader UI component - * - * @param Type $entityType - * @param Attribute $attribute - * @param array $customerData - * @return array - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function getFileUploaderData( - Type $entityType, - Attribute $attribute, - array $customerData - ): array { - $attributeCode = $attribute->getAttributeCode(); - - $file = $customerData[$attributeCode] ?? ''; - - /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->fileProcessorFactory->create([ - 'entityTypeCode' => $entityType->getEntityTypeCode(), - ]); - - if (!empty($file) - && $fileProcessor->isExist($file) - ) { - $stat = $fileProcessor->getStat($file); - $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); - - return [ - [ - 'file' => $file, - 'size' => null !== $stat ? $stat['size'] : 0, - 'url' => $viewUrl ?? '', - 'name' => basename($file), - 'type' => $fileProcessor->getMimeType($file), - ], - ]; - } - - return []; - } - /** * Get attributes meta * @@ -334,209 +190,15 @@ protected function getAttributesMeta(Type $entityType): array $attributes = $entityType->getAttributeCollection(); /* @var AbstractAttribute $attribute */ foreach ($attributes as $attribute) { - $this->processFrontendInput($attribute, $meta); - - $code = $attribute->getAttributeCode(); - - // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value - foreach ($this->metaProperties as $metaName => $origName) { - $value = $attribute->getDataUsingMethod($origName); - $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; - if ('frontend_input' === $origName) { - $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; - } - } - - if ($attribute->usesSource()) { - if ($code == AddressInterface::COUNTRY_ID) { - $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource - ->getAllOptions(); - } else { - $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); - } - } - - $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); - if (!empty($rules)) { - $meta[$code]['arguments']['data']['config']['validation'] = $rules; - } - - $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; - $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); - - $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + $meta[$attribute->getAttributeCode()] = $this->attributeMetadataResolver->getAttributesMeta( + $attribute, + $entityType, + $this->allowToShowHiddenAttributes, + $this->getRequestFieldName() + ); } + $this->attributeMetadataResolver->processWebsiteMeta($meta); - $this->processWebsiteMeta($meta); return $meta; } - - /** - * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttributeInForm(AbstractAttribute $customerAttribute) - { - $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; - - if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { - return \is_array($customerAttribute->getUsedInForms()) && - ( - (\in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || - (\in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) - ); - } - return \is_array($customerAttribute->getUsedInForms()) && - \in_array('customer_address_edit', $customerAttribute->getUsedInForms()); - } - - /** - * Detect can we show attribute on specific form or not - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttribute(AbstractAttribute $customerAttribute) - { - $userDefined = (bool) $customerAttribute->getIsUserDefined(); - if (!$userDefined) { - return $customerAttribute->getIsVisible(); - } - - $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); - - return ($this->allowToShowHiddenAttributes && $canShowOnForm) || - (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); - } - - /** - * Add global scope parameter and filter options to website meta - * - * @param array $meta - * @return void - */ - private function processWebsiteMeta(&$meta) - { - if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { - $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; - } - - if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { - $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ - 'target' => '${ $.provider }:data.customer.website_id', - 'field' => 'website_ids' - ]; - } - } - - /** - * Override file uploader UI component metadata - * - * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Type $entityType - * @param AbstractAttribute $attribute - * @param array $config - * @return void - */ - private function overrideFileUploaderMetadata( - Type $entityType, - AbstractAttribute $attribute, - array &$config - ) { - if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $maxFileSize = self::MAX_FILE_SIZE; - - if (isset($config['validation']['max_file_size'])) { - $maxFileSize = (int)$config['validation']['max_file_size']; - } - - $allowedExtensions = []; - - if (isset($config['validation']['file_extensions'])) { - $allowedExtensions = explode(',', $config['validation']['file_extensions']); - array_walk($allowedExtensions, function (&$value) { - $value = strtolower(trim($value)); - }); - } - - $allowedExtensions = implode(' ', $allowedExtensions); - - $entityTypeCode = $entityType->getEntityTypeCode(); - $url = $this->getFileUploadUrl($entityTypeCode); - - $config = [ - 'formElement' => 'fileUploader', - 'componentType' => 'fileUploader', - 'maxFileSize' => $maxFileSize, - 'allowedExtensions' => $allowedExtensions, - 'uploaderConfig' => [ - 'url' => $url, - ], - 'label' => $this->getMetadataValue($config, 'label'), - 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), - 'required' => $this->getMetadataValue($config, 'required'), - 'visible' => $this->getMetadataValue($config, 'visible'), - 'validation' => $this->getMetadataValue($config, 'validation'), - ]; - } - } - - /** - * Retrieve metadata value - * - * @param array $config - * @param string $name - * @param mixed $default - * @return mixed - */ - private function getMetadataValue($config, $name, $default = null) - { - return $config[$name] ?? $default; - } - - /** - * Retrieve URL to file upload - * - * @param string $entityTypeCode - * @return string - */ - private function getFileUploadUrl($entityTypeCode): string - { - switch ($entityTypeCode) { - case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: - $url = 'customer/file/customer_upload'; - break; - - case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: - $url = 'customer/file/address_upload'; - break; - - default: - $url = ''; - break; - } - return $url; - } - - /** - * Process attributes by frontend input type - * - * @param AttributeInterface $attribute - * @param array $meta - * @return void - */ - private function processFrontendInput(AttributeInterface $attribute, array &$meta) - { - $code = $attribute->getAttributeCode(); - if ($attribute->getFrontendInput() === 'boolean') { - $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; - $meta[$code]['arguments']['data']['config']['valueMap'] = [ - 'true' => '1', - 'false' => '0', - ]; - } - } } diff --git a/app/code/Magento/Customer/Model/FileUploaderDataResolver.php b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php new file mode 100644 index 0000000000000..a132507deaa2f --- /dev/null +++ b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php @@ -0,0 +1,201 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model; + +use Magento\Eav\Model\Entity\Type; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\CustomerMetadataInterface; + +/** + * Class to retrieve file uploader data for customer and customer address file & image attributes + */ +class FileUploaderDataResolver +{ + /** + * Maximum file size allowed for file_uploader UI component + */ + private const MAX_FILE_SIZE = 2097152; + + /** + * @var FileProcessorFactory + */ + private $fileProcessorFactory; + + /** + * File types allowed for file_uploader UI component + * + * @var array + */ + private $fileUploaderTypes = [ + 'image', + 'file', + ]; + + /** + * @param FileProcessorFactory $fileProcessorFactory + */ + public function __construct(FileProcessorFactory $fileProcessorFactory) { + $this->fileProcessorFactory = $fileProcessorFactory; + } + + /** + * Override file uploader UI component data + * + * Overrides data for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Customer|Address $entity + * @param array $entityData + * @return void + */ + public function overrideFileUploaderData($entity, array &$entityData): void + { + $attributes = $entity->getAttributes(); + foreach ($attributes as $attribute) { + /** @var Attribute $attribute */ + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes, true)) { + $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( + $entity->getEntityType(), + $attribute, + $entityData + ); + } + } + } + + /** + * Retrieve array of values required by file uploader UI component + * + * @param Type $entityType + * @param Attribute $attribute + * @param array $customerData + * @return array + */ + private function getFileUploaderData( + Type $entityType, + Attribute $attribute, + array $customerData + ): array { + $attributeCode = $attribute->getAttributeCode(); + + $file = $customerData[$attributeCode] ?? ''; + + /** @var FileProcessor $fileProcessor */ + $fileProcessor = $this->fileProcessorFactory->create([ + 'entityTypeCode' => $entityType->getEntityTypeCode(), + ]); + + if (!empty($file) + && $fileProcessor->isExist($file) + ) { + $stat = $fileProcessor->getStat($file); + $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); + + return [ + [ + 'file' => $file, + 'size' => null !== $stat ? $stat['size'] : 0, + 'url' => $viewUrl ?? '', + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), + ], + ]; + } + + return []; + } + + /** + * Override file uploader UI component metadata + * + * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Type $entityType + * @param AbstractAttribute $attribute + * @param array $config + * @return void + */ + public function overrideFileUploaderMetadata( + Type $entityType, + AbstractAttribute $attribute, + array &$config + ): void { + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes, true)) { + $maxFileSize = self::MAX_FILE_SIZE; + + if (isset($config['validation']['max_file_size'])) { + $maxFileSize = (int)$config['validation']['max_file_size']; + } + + $allowedExtensions = []; + + if (isset($config['validation']['file_extensions'])) { + $allowedExtensions = explode(',', $config['validation']['file_extensions']); + array_walk($allowedExtensions, function (&$value) { + $value = strtolower(trim($value)); + }); + } + + $allowedExtensions = implode(' ', $allowedExtensions); + + $entityTypeCode = $entityType->getEntityTypeCode(); + $url = $this->getFileUploadUrl($entityTypeCode); + + $config = [ + 'formElement' => 'fileUploader', + 'componentType' => 'fileUploader', + 'maxFileSize' => $maxFileSize, + 'allowedExtensions' => $allowedExtensions, + 'uploaderConfig' => [ + 'url' => $url, + ], + 'label' => $this->getMetadataValue($config, 'label'), + 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), + 'required' => $this->getMetadataValue($config, 'required'), + 'visible' => $this->getMetadataValue($config, 'visible'), + 'validation' => $this->getMetadataValue($config, 'validation'), + ]; + } + } + + /** + * Retrieve metadata value + * + * @param array $config + * @param string $name + * @param mixed $default + * @return mixed + */ + private function getMetadataValue($config, $name, $default = null) + { + return $config[$name] ?? $default; + } + + /** + * Retrieve URL to file upload + * + * @param string $entityTypeCode + * @return string + */ + private function getFileUploadUrl($entityTypeCode): string + { + switch ($entityTypeCode) { + case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: + $url = 'customer/file/customer_upload'; + break; + + case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: + $url = 'customer/file/address_upload'; + break; + + default: + $url = ''; + break; + } + return $url; + } +} diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 9e432f9f10e0c..1c30d08879eed 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -60,7 +60,7 @@ <dataType>text</dataType> </settings> </field> - <field name="default_billing" sortOrder="1" formElement="checkbox"> + <field name="default_billing" sortOrder="10" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> @@ -83,7 +83,7 @@ </checkbox> </formElements> </field> - <field name="default_shipping" sortOrder="0" formElement="checkbox"> + <field name="default_shipping" sortOrder="5" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js deleted file mode 100644 index a715aae1ebd96..0000000000000 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'jquery', - 'uiElement' -], function($, Component) { - 'use strict'; - - return Component.extend({ - defaults: { - template: 'Magento_Customer/default-address' - } - }); -}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js deleted file mode 100644 index 94701f4c1af99..0000000000000 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'jquery', - 'Magento_Ui/js/modal/modal-component', - 'uiRegistry', - 'underscore' -], function ($, Modal, registry, _) { - 'use strict'; - - return Modal.extend({ - defaults: { - modules: { - emailProvider: '${ $.emailProvider }' - } - }, - - /** - * Initializes component. - * - * @returns {Object} Chainable. - */ - initialize: function () { - this._super(); - - // console.log(this.name); - - return this; - }, - - /** - * Open modal. - */ - openModal: function (data) { - debugger; - if (data == null){ - // add - this.setTitle(this.options.title); - this._super(); - } else { - // edit - var addressId = data.uuid; - var address = { - 'city': 'city', - 'company': 'company', - 'country_id': 'country_id', - 'customer_id': 'customer_id', - 'created_at': 'created_at', - 'default_billing': 'default_billing', - 'default_shipping': 'default_shipping', - 'entity_id': 'entity_id', - 'fax': 'fax', - 'firstname': 'firstname', - 'increment_id': 'increment_id', - 'is_active': 'is_active', - 'lastname': 'lastname', - 'middlename': 'middlename', - 'parent_id': 'parent_id', - 'postcode': 'postcode', - 'prefix': 'prefix', - 'region': 'region', - 'region_id': 'region_id', - 'street': [0, 1], - 'suffix': 'suffix', - 'telephone': 'telephone', - 'updated_at': 'updated_at', - 'vat_id': 'vat_id', - 'vat_is_valid': 'vat_is_valid', - 'vat_request_date': 'vat_request_date', - 'vat_request_id': 'vat_request_id', - 'vat_request_success': 'vat_request_success' - }; - - var source = registry.get('customer_form.customer_form_data_source'); - var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; - - _.each(address, function(value, key) { - if (key === 'default_billing' || key === 'default_shipping') { - var defaultValue = source.get('data.address.' + addressId + '.' + value); - // convert boolean to integer - var val = +defaultValue; - source.set(modal + '.' + key, val.toString()); - } else if (key === 'street' && _.isArray(address[key])) { - _.each(address[key], function(element, index) { - source.set(modal + '.' + key + '[' + index + ']', source.get('data.address.' + addressId + '.' + key + '.' + element)); - }); - } else { - source.set(modal + '.' + key, source.get('data.address.' + addressId + '.' + value)); - } - }); - - this.setTitle(this.options.title); - this._super(); - } - }, - - /** - * Close popup modal. - * @public - */ - closeModal: function () { - debugger; - this._clearData(); - this._super(); - }, - - /** - * Clear modal data. - * - * @private - */ - _clearData: function () { - debugger; - var address = { - 'city': '', - 'company': '', - 'country_id': '', - 'default_billing': "0", - 'default_shipping': "0", - 'entity_id': '', - 'firstname': '', - 'is_active': '', - 'lastname': '', - 'middlename': '', - 'postcode': '', - 'prefix': '', - 'region': '', - 'region_id': '', - 'street[0]': '', - 'street[1]': '', - 'suffix': '', - 'telephone': '', - 'vat_id': '' - }; - - var source = registry.get('customer_form.customer_form_data_source'); - var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; - - _.each(address, function(value, key) { - source.set(modal + '.' + key, value); - }); - }, - - /** - * Open modal. - */ - save: function () { - debugger; - - var address = { - 'city': 'city', - 'company': 'company', - 'country_id': 'country_id', - 'customer_id': 'customer_id', - 'created_at': 'created_at', - 'default_billing': 'default_billing', - 'default_shipping': 'default_shipping', - 'entity_id': 'entity_id', - 'fax': 'fax', - 'firstname': 'firstname', - 'increment_id': 'increment_id', - 'is_active': 'is_active', - 'lastname': 'lastname', - 'middlename': 'middlename', - 'parent_id': 'parent_id', - 'postcode': 'postcode', - 'prefix': 'prefix', - 'region': 'region', - 'region_id': 'region_id', - 'street': ['street[0]', 'street[1]'], - 'suffix': 'region_id', - 'telephone': 'telephone', - 'updated_at': 'updated_at', - 'vat_id': 'vat_id', - 'vat_is_valid': 'vat_is_valid', - 'vat_request_date': 'vat_request_date', - 'vat_request_id': 'vat_request_id', - 'vat_request_success': 'vat_request_success' - }; - - var source = registry.get('customer_form.customer_form_data_source'); - var formData = source.get('data.address_listing.address_form.update_customer_address_form_modal'); - var entityId = formData.entity_id; - - $.ajax({ - url: this.options.url, - showLoader: true, - data: formData, - type: "POST", - dataType: 'json', - success: function(data) { - console.log('SUCCESS: ', data); - }, - error: function(data) { - console.log('ERROR: ', data); - } - }); - } - }); -}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js deleted file mode 100644 index edfb004654a9b..0000000000000 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'Magento_Ui/js/form/components/insert-form' -], function (Insert) { - 'use strict'; - - return Insert.extend({ - // Should be refactored after form save.!!!!! - // defaults: { - // updateModalProvider: '${ $.parentName }', - // subTitlePrefix: $t('Belongs to '), - // switcherSelector: '.store-switcher', - // toRemove: [], - // // imports: { - // // removeResponseData: '${ $.removeResponseProvider }', - // // modalTitle: '${ $.modalTitleProvider }', - // // modalSubTitle: '${ $.modalSubTitleProvider }', - // // destroyClosedModalContents: '${ $.updateModalProvider }:state' - // // }, - // // listens: { - // // responseData: 'afterUpdate', - // // removeResponseData: 'afterRemove', - // // modalTitle: 'changeModalTitle', - // // modalSubTitle: 'changeModalSubTitle' - // // }, - // modules: { - // updateModal: '${ $.updateModalProvider }', - // removeModal: '${ $.removeModalProvider }', - // upcomingListing: 'index = ${ $.upcomingListingProvider }' - // } - // }, - // - // /** @inheritdoc **/ - // initialize: function () { - // _.bindAll(this, 'onSwitcherSelect'); - // this._super(); - // this.updateModal(this.initSwitcherHandler.bind(this)); - // - // return this; - // }, - // - // initConfig: function (options) { - // debugger; - // return this._super(); - // }, - // - // /** @inheritdoc */ - // destroyInserted: function () { - // if (this.isRendered) { - // _.each(this.toRemove, function (componentName) { - // registry.get(componentName, function (component) { - // if (component.hasOwnProperty('delegate')) { - // component.delegate('destroy'); - // } else { - // component.destroy(); - // } - // }); - // }); - // } - // - // this._super(); - // }, - // - // // /** - // // * Form save callback. - // // * - // // * @param {Object} data - // // */ - // // afterUpdate: function (data) { - // // if (!data.error) { - // // this.updateModal('closeModal'); - // // this.upcomingListing('reload'); - // // } - // // }, - // - // // /** - // // * Form remove callback. - // // * - // // * @param {Object} data - // // */ - // // afterRemove: function (data) { - // // if (!data.error) { - // // this.removeModal('closeModal'); - // // this.afterUpdate(data); - // // } - // // }, - // - // // /** - // // * Change modal title. - // // * - // // * @param {String} title - // // */ - // // changeModalTitle: function (title) { - // // this.updateModal('setTitle', title); - // // }, - // // - // // /** - // // * Change modal sub title. - // // * - // // * @param {String} subTitle - // // */ - // // changeModalSubTitle: function (subTitle) { - // // subTitle = subTitle ? - // // this.subTitlePrefix + this.modalTitle + ' ' + subTitle : - // // ''; - // // - // // this.updateModal('setSubTitle', subTitle); - // // }, - // - // /** - // * Destroy contents of modal when it is closed - // * - // * @param {Boolean} state - // */ - // destroyClosedModalContents: function (state) { - // if (state === false) { - // this.destroyInserted(); - // } - // }, - // - // /** - // * Switcher initialization. - // */ - // initSwitcherHandler: function () { - // var switcherSelector = this.updateModal().rootSelector + ' ' + this.switcherSelector, - // self = this; - // - // $.async(switcherSelector, function (switcher) { - // $(switcher).on('click', 'li a', self.onSwitcherSelect); - // }); - // }, - // - // /** - // * Store switcher selection handler. - // * @param {Object} e - event object. - // */ - // onSwitcherSelect: function (e) { - // var self = this, - // param = $(e.currentTarget).data('param'), - // params = { - // store: 0 - // }; - // - // params[param] = $(e.currentTarget).data('value'); - // - // uiConfirm({ - // content: $t('Please confirm scope switching. All data that hasn\'t been saved will be lost.'), - // actions: { - // - // /** Confirm callback. */ - // confirm: function () { - // self.destroyInserted(); - // params = _.extend(self.previousParams, params); - // self.render(params); - // } - // } - // }); - // } - }); -}); diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 1eb3652628c28..6fc8fcac6099f 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -351,7 +351,7 @@ </argument> <settings> <componentType>button</componentType> - <title>Edit + Edit true ${ $.provider}:data.default_billing_address.entity_id @@ -398,7 +398,7 @@ button - Edit + Edit true ${ $.provider}:data.default_shipping_address.entity_id @@ -428,7 +428,7 @@ - Add New Address + Add New Address ${ $.provider}:data.customer_id @@ -440,9 +440,8 @@ - + - customer_address_edit 1 diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js index dbea61b13e626..96d2a9e83a8f5 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js @@ -5,9 +5,6 @@ /** * @api - * @deprecated as customer addresses are handled by ui components. - * This collection component manages rendering address list in Addresses tab of customer. - * Now address list is rendered with ui component listing. */ define([ 'underscore', @@ -49,7 +46,6 @@ define([ * @param {Object} elem - Incoming child. */ initElement: function (elem) { - debugger; this._super(); elem.activate(); diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js index ae7f375bdca02..045c25ab7911f 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js @@ -5,9 +5,6 @@ /** * @api - * @deprecated as customer addresses are handled by ui components. - * This item component renders address list item preview in Addresses tab. - * But now address list item is rendered with ui component in customer form. */ define([ 'underscore', diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt index 5c5c380c4dd33..877583e5b6a29 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt @@ -1 +1 @@ -# Format: or simply \ No newline at end of file +# Format: or simply diff --git a/setup/performance-toolkit/config/customerConfig.xml b/setup/performance-toolkit/config/customerConfig.xml index b77d9f6d4c941..8fd74d7b53885 100644 --- a/setup/performance-toolkit/config/customerConfig.xml +++ b/setup/performance-toolkit/config/customerConfig.xml @@ -6,5 +6,5 @@ */ --> - 5 + 2 From 052d0cc0dda65fa2a014cd0c6a3925b2d14c3f12 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Tue, 30 Oct 2018 13:20:37 -0500 Subject: [PATCH 0368/1158] MAGETWO-95773: Credit memo is created instead of returning error via invoice refund API for Bundle product - add error message for incorrect product items --- .../Item/Validation/CreationQuantityValidator.php | 4 ++++ app/code/Magento/Sales/Model/Order/ItemRepository.php | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php index 0c2adfff80a2b..fdc5e2658b9ed 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php @@ -53,6 +53,10 @@ public function validate($entity) return [__('The creditmemo contains product item that is not part of the original order.')]; } + if ($orderItem->isDummy()) { + return [__('The creditmemo contains incorrect product items.')]; + } + if (!$this->isQtyAvailable($orderItem, $entity->getQty())) { return [__('The quantity to refund must not be greater than the unrefunded quantity.')]; } diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index 7916eb9db2b80..2ea9831336cc2 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -228,6 +228,12 @@ private function addParentItem(OrderItemInterface $orderItem) { if ($parentId = $orderItem->getParentItemId()) { $orderItem->setParentItem($this->get($parentId)); + } else { + foreach ($orderItem->getOrder()->getAllItems() as $item) { + if($item->getParentItemId() === $orderItem->getItemId()) { + $item->setParentItem($orderItem); + } + } } } From 970a746e1274419973be563ffd8e3a49a8cb26ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:13:56 +0200 Subject: [PATCH 0369/1158] Update _module.less code clean up --- .../Magento_MultipleWishlist/web/css/source/_module.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less index 145dc10263fb1..cb341f3f479ba 100644 --- a/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less @@ -185,7 +185,7 @@ } .form-wishlist-search { - .lib-css(margin-bottom, @indent__l*2); + margin-bottom: @indent__l * 2; max-width: 500px; .fieldset { @@ -216,8 +216,9 @@ .block-wishlist-info-items { .block-title { - .lib-css(margin-bottom, @indent__base); .lib-font-size(22); + margin-bottom: @indent__base; + > strong { font-weight: @font-weight__light; } From c7aa2f7def099baefda795e3ff64ea26e8ce1d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:24:33 +0200 Subject: [PATCH 0370/1158] Update _module.less --- .../Magento_MultipleWishlist/web/css/source/_module.less | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/design/frontend/Magento/luma/Magento_MultipleWishlist/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_MultipleWishlist/web/css/source/_module.less index 6ab7a8e47a174..0b01c54a64378 100644 --- a/app/design/frontend/Magento/luma/Magento_MultipleWishlist/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_MultipleWishlist/web/css/source/_module.less @@ -40,6 +40,7 @@ .items { padding: 6px 0; text-align: left; + .item { > span { display: block; @@ -47,6 +48,7 @@ } } + li { padding: 0; } @@ -115,6 +117,7 @@ &.split, &.toggle { .lib-css(color, @link__color); + &:before { display: none; } @@ -135,6 +138,7 @@ &.overlay { .lib-window-overlay(); + &.active { display: block; } @@ -254,7 +258,7 @@ } .form-wishlist-search { - .lib-css(margin-bottom, @indent__l*2); + margin-bottom: @indent__l * 2; max-width: 500px; .fieldset { @@ -281,7 +285,7 @@ .block-wishlist-info-items { .block-title { - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; .lib-font-size(22px); > strong { @@ -352,6 +356,7 @@ // Select wish list &-select { margin: 0 -@layout__width-xs-indent 20px; + .wishlist-name { .lib-font-size(16); &:extend(.abs-toggling-title-mobile all); From b0fca1d57b6b9352e62f8059e58f5d62bf8c45d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:31:16 +0200 Subject: [PATCH 0371/1158] Update _widgets.less --- .../Magento/blank/Magento_Banner/web/css/source/_widgets.less | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less index 80ac77e42fc04..c961d49c5b589 100644 --- a/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less @@ -8,7 +8,6 @@ // _____________________________________________ & when (@media-common = true) { - .block-banners, .block-banners-inline { &:extend(.abs-margin-for-blocks-and-widgets); @@ -22,7 +21,7 @@ } .banner-item-content { - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; img { display: block; From b198d34bda628bc022bef79767cacbb075c1d62c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:37:50 +0200 Subject: [PATCH 0372/1158] Update _minicart.less --- .../web/css/source/module/_minicart.less | 62 ++++++++++--------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less index 7bd27106b67d9..2219db1cf694d 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less @@ -125,7 +125,7 @@ float: right; .block-minicart { - .lib-css(padding, 25px @minicart__padding-horizontal); + padding: 25px @minicart__padding-horizontal; .block-title { display: none; @@ -148,10 +148,10 @@ .action { &.close { .lib-button-icon( - @icon-remove, - @_icon-font-size: 32px, - @_icon-font-line-height: 32px, - @_icon-font-text-hide: true + @icon-remove, + @_icon-font-size: 32px, + @_icon-font-line-height: 32px, + @_icon-font-text-hide: true ); .lib-button-reset(); height: 40px; @@ -205,8 +205,8 @@ } .minicart-items-wrapper { - .lib-css(border, 1px solid @minicart__border-color); - .lib-css(margin, 0 -@minicart__padding-horizontal); + border: 1px solid @minicart__border-color; + margin: 0 -@minicart__padding-horizontal; border-left: 0; border-right: 0; overflow-x: auto; @@ -220,7 +220,7 @@ padding: @indent__base 0; &:not(:first-child) { - .lib-css(border-top, 1px solid @minicart__border-color); + border-top: 1px solid @minicart__border-color; } &:first-child { @@ -254,12 +254,12 @@ .toggle { .lib-icon-font( - @_icon-font-content: @icon-down, - @_icon-font-size: 28px, - @_icon-font-line-height: 16px, - @_icon-font-text-hide: false, - @_icon-font-position: after, - @_icon-font-display: block + @_icon-font-content: @icon-down, + @_icon-font-size: 28px, + @_icon-font-line-height: 16px, + @_icon-font-text-hide: false, + @_icon-font-position: after, + @_icon-font-display: block ); cursor: pointer; position: relative; @@ -274,8 +274,8 @@ &.active { > .toggle { .lib-icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after + @_icon-font-content: @icon-up, + @_icon-font-position: after ); } } @@ -304,6 +304,7 @@ .weee[data-label] { .lib-font-size(11); + .label { &:extend(.abs-no-display all); } @@ -317,12 +318,12 @@ .product.options { .tooltip.toggle { .lib-icon-font( - @icon-down, - @_icon-font-size: 28px, - @_icon-font-line-height: 28px, - @_icon-font-text-hide: true, - @_icon-font-margin: -3px 0 0 7px, - @_icon-font-position: after + @icon-down, + @_icon-font-size: 28px, + @_icon-font-line-height: 28px, + @_icon-font-text-hide: true, + @_icon-font-margin: -3px 0 0 7px, + @_icon-font-position: after ); .details { @@ -357,19 +358,19 @@ &.edit, &.delete { .lib-icon-font( - @icon-settings, - @_icon-font-size: 28px, - @_icon-font-line-height: 28px, - @_icon-font-text-hide: true, - @_icon-font-color: @color-gray19, - @_icon-font-color-hover: @color-gray19, - @_icon-font-color-active: @color-gray19 + @icon-settings, + @_icon-font-size: 28px, + @_icon-font-line-height: 28px, + @_icon-font-text-hide: true, + @_icon-font-color: @color-gray19, + @_icon-font-color-hover: @color-gray19, + @_icon-font-color-active: @color-gray19 ); } &.delete { .lib-icon-font-symbol( - @_icon-font-content: @icon-trash + @_icon-font-content: @icon-trash ); } } @@ -399,6 +400,7 @@ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .minicart-wrapper { margin-left: 13px; + .block-minicart { right: -15px; width: 390px; From b48b95f0c6027e7bf93ce49297c4cb04b567b577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:42:18 +0200 Subject: [PATCH 0373/1158] Update _minicart.less --- .../web/css/source/module/_minicart.less | 77 ++++++++++--------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less index 03e4bfff3ba9c..14db9dd868e00 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less @@ -107,28 +107,28 @@ .minicart-wrapper { .lib-dropdown( - @_toggle-selector: ~'.action.showcart', - @_options-selector: ~'.block-minicart', - @_dropdown-list-width: 320px, - @_dropdown-list-position-right: 0px, - @_dropdown-list-pointer-position: right, - @_dropdown-list-pointer-position-left-right: 26px, - @_dropdown-list-z-index: 101, - @_dropdown-toggle-icon-content: @icon-cart, - @_dropdown-toggle-active-icon-content: @icon-cart, - @_dropdown-list-item-padding: false, - @_dropdown-list-item-hover: false, - @_icon-font-position: before, - @_icon-font-size: 22px, - @_icon-font-line-height: 28px, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @minicart-icons-color-hover, - @_icon-font-color-active: @minicart-icons-color + @_toggle-selector: ~'.action.showcart', + @_options-selector: ~'.block-minicart', + @_dropdown-list-width: 320px, + @_dropdown-list-position-right: 0px, + @_dropdown-list-pointer-position: right, + @_dropdown-list-pointer-position-left-right: 26px, + @_dropdown-list-z-index: 101, + @_dropdown-toggle-icon-content: @icon-cart, + @_dropdown-toggle-active-icon-content: @icon-cart, + @_dropdown-list-item-padding: false, + @_dropdown-list-item-hover: false, + @_icon-font-position: before, + @_icon-font-size: 22px, + @_icon-font-line-height: 28px, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @minicart-icons-color-hover, + @_icon-font-color-active: @minicart-icons-color ); float: right; .block-minicart { - .lib-css(padding, 25px @minicart__padding-horizontal); + padding: 25px @minicart__padding-horizontal; .block-title { display: none; @@ -216,8 +216,8 @@ } .minicart-items-wrapper { - .lib-css(border, 1px solid @minicart__border-color); - .lib-css(margin, 0 -@minicart__padding-horizontal); + border: 1px solid @minicart__border-color; + margin: 0 -@minicart__padding-horizontal; border-left: 0; border-right: 0; overflow-x: auto; @@ -226,11 +226,12 @@ .minicart-items { .lib-list-reset-styles(); + .product-item { padding: @indent__base 0; &:not(:first-child) { - .lib-css(border-top, 1px solid @minicart__border-color); + border-top: 1px solid @minicart__border-color; } &:first-child { @@ -297,13 +298,14 @@ .toggle { &:extend(.abs-toggling-title all); + border: 0; + padding: 0 @indent__xl @indent__xs 0; + &:after { .lib-css(color, @color-gray56); margin: 0 0 0 @indent__xs; position: static; } - border: 0; - padding: 0 @indent__xl @indent__xs 0; } .active { @@ -323,14 +325,15 @@ .toggle { &.tooltip { .lib-icon-font( - @icon-down, - @_icon-font-size: 12px, - @_icon-font-line-height: 12px, - @_icon-font-text-hide: true, - @_icon-font-margin: -3px 0 0 7px, - @_icon-font-position: after + @icon-down, + @_icon-font-size: 12px, + @_icon-font-line-height: 12px, + @_icon-font-text-hide: true, + @_icon-font-margin: -3px 0 0 7px, + @_icon-font-position: after ); } + > span { &:extend(.abs-visually-hidden-reset all); } @@ -368,19 +371,19 @@ &.edit, &.delete { .lib-icon-font( - @icon-edit, - @_icon-font-size: 18px, - @_icon-font-line-height: 20px, - @_icon-font-text-hide: true, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @primary__color, - @_icon-font-color-active: @minicart-icons-color + @icon-edit, + @_icon-font-size: 18px, + @_icon-font-line-height: 20px, + @_icon-font-text-hide: true, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @primary__color, + @_icon-font-color-active: @minicart-icons-color ); } &.delete { .lib-icon-font-symbol( - @_icon-font-content: @icon-trash + @_icon-font-content: @icon-trash ); } } From ecaabe44f4264d90a63c3fb3624bb04e47f9e661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:50:39 +0200 Subject: [PATCH 0374/1158] Update _module.less --- .../Magento_Review/web/css/source/_module.less | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less index 7d5b79bc5a091..69ec01d71e104 100644 --- a/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less @@ -15,9 +15,9 @@ // _____________________________________________ & when (@media-common = true) { - .rating-summary { .lib-rating-summary(); + .rating-result { margin-left: -5px; } @@ -165,10 +165,10 @@ .review-details { .customer-review-rating { - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; .item { - .lib-css(margin-bottom, @indent__s); + margin-bottom: @indent__s; &:last-child { margin-bottom: 0; @@ -178,12 +178,12 @@ .review-title { .lib-heading(h3); - .lib-css(font-weight, @font-weight__semibold); - .lib-css(margin-bottom, @indent__base); + font-weight: @font-weight__semibold; + margin-bottom: @indent__base; } .review-content { - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; } } @@ -271,7 +271,7 @@ &-field-rating { .control { - margin-bottom: 1.2*@indent__xl; + margin-bottom: 1.2 * @indent__xl; margin-top: @indent__s; } } From a02c49ffeddd25852bc6bb2b5709c513c946c5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 21:56:32 +0200 Subject: [PATCH 0375/1158] Update _module.less --- .../web/css/source/_module.less | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/app/design/frontend/Magento/luma/Magento_Review/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Review/web/css/source/_module.less index da78406f92212..2c66420f65fbd 100644 --- a/app/design/frontend/Magento/luma/Magento_Review/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Review/web/css/source/_module.less @@ -14,7 +14,6 @@ // _____________________________________________ & when (@media-common = true) { - .data.switch .counter { .lib-css(color, @text__color__muted); @@ -118,13 +117,13 @@ strong { display: block; - font-weight: 600; + font-weight: @font-weight__semibold; } } .fieldset &-field-ratings { > .label { - font-weight: 600; + font-weight: @font-weight__semibold; margin-bottom: @indent__s; padding: 0; } @@ -140,11 +139,11 @@ &-field-rating { .label { - font-weight: 600; + font-weight: @font-weight__semibold; } .control { - margin-bottom: 1.2*@indent__xl; + margin-bottom: 1.2 * @indent__xl; margin-top: @indent__s; } } @@ -181,7 +180,7 @@ display: inline; .review-details-value { - font-weight: 400; + font-weight: @font-weight__regular; } } @@ -341,7 +340,7 @@ .block-reviews-dashboard { .items { .item { - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; &:last-child { margin-bottom: 0; @@ -353,14 +352,14 @@ display: inline-block; &:not(:last-child) { - .lib-css(margin-bottom, @indent__xs); + margin-bottom: @indent__xs; } } .rating-summary { .label { - .lib-css(font-weight, @font-weight__semibold); - .lib-css(margin-right, @indent__s); + font-weight: @font-weight__semibold; + margin-right: @indent__s; } } } @@ -368,7 +367,7 @@ .table-reviews, .block-reviews-dashboard { .product-name { - .lib-css(font-weight, @font-weight__regular); + font-weight: @font-weight__regular; } } @@ -416,6 +415,7 @@ .product-details { &:extend(.abs-add-clearfix all); &:extend(.abs-margin-for-blocks-and-widgets all); + .rating-average-label { &:extend(.abs-visually-hidden all); } @@ -436,9 +436,10 @@ } .customer-review-rating { - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; + .item { - .lib-css(margin-bottom, @indent__s); + margin-bottom: @indent__s; &:last-child { margin-bottom: 0; @@ -450,13 +451,13 @@ .review-title { .lib-heading(h3); - .lib-css(font-weight, @font-weight__semibold); - .lib-css(margin-bottom, @indent__base); + font-weight: @font-weight__semibold; + margin-bottom: @indent__base; } .review-content { margin: 0; - .lib-css(margin-bottom, @indent__base); + margin-bottom: @indent__base; } .review-date { @@ -473,13 +474,13 @@ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .customer-review { .product-name { - .lib-css(margin-bottom, @indent__xs); + margin-bottom: @indent__xs; } .product-reviews-summary { .rating-summary { display: block; - .lib-css(margin-bottom, @indent__xs); + margin-bottom: @indent__xs; } } } From 59a88f3509bba27c988fc89f874cdaf7f0d5c29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 22:08:34 +0200 Subject: [PATCH 0376/1158] Update _extends.less --- .../blank/web/css/source/_extends.less | 191 +++++++++--------- 1 file changed, 96 insertions(+), 95 deletions(-) diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less index 13da4a4d996cc..4b328ab1015ed 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_extends.less +++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less @@ -162,7 +162,7 @@ & when (@media-common = true) { .abs-login-block-title { strong { - font-weight: 500; + font-weight: @font-weight__heavier; } .lib-font-size(18); @@ -178,11 +178,11 @@ & when (@media-common = true) { .abs-block-title { + margin-bottom: 15px; + > strong { .lib-heading(h3); } - - margin-bottom: 15px; } } @@ -194,6 +194,7 @@ .abs-account-blocks { .block-title { &:extend(.abs-block-title all); + > .action { margin-left: 15px; } @@ -208,7 +209,7 @@ } > .action { - font-weight: 400; + font-weight: @font-weight__regular; margin-left: @indent__s; } } @@ -232,10 +233,10 @@ & when (@media-common = true) { .abs-dropdown-simple { .lib-dropdown( - @_dropdown-list-item-padding: 5px 5px 5px 23px, - @_dropdown-list-min-width: 200px, - @_icon-font-margin: 0 0 0 5px, - @_icon-font-vertical-align: middle + @_dropdown-list-item-padding: 5px 5px 5px 23px, + @_dropdown-list-min-width: 200px, + @_icon-font-margin: 0 0 0 5px, + @_icon-font-vertical-align: middle ); } } @@ -268,13 +269,13 @@ & when (@media-common = true) { .abs-remove-button-for-blocks { .lib-icon-font( - @icon-remove, - @_icon-font-size: 26px, - @_icon-font-line-height: 15px, - @_icon-font-text-hide: true, - @_icon-font-color: @color-gray19, - @_icon-font-color-hover: @color-gray19, - @_icon-font-color-active: @color-gray19 + @icon-remove, + @_icon-font-size: 26px, + @_icon-font-line-height: 15px, + @_icon-font-text-hide: true, + @_icon-font-color: @color-gray19, + @_icon-font-color-hover: @color-gray19, + @_icon-font-color-active: @color-gray19 ); } } @@ -289,14 +290,14 @@ > a { .lib-link( - @_link-color: @product-name-link__color, - @_link-text-decoration: @product-name-link__text-decoration, - @_link-color-visited: @product-name-link__color__visited, - @_link-text-decoration-visited: @product-name-link__text-decoration__visited, - @_link-color-hover: @product-name-link__color__hover, - @_link-text-decoration-hover: @product-name-link__text-decoration__hover, - @_link-color-active: @product-name-link__color__active, - @_link-text-decoration-active: @product-name-link__text-decoration__active + @_link-color: @product-name-link__color, + @_link-text-decoration: @product-name-link__text-decoration, + @_link-color-visited: @product-name-link__color__visited, + @_link-text-decoration-visited: @product-name-link__text-decoration__visited, + @_link-color-hover: @product-name-link__color__hover, + @_link-text-decoration-hover: @product-name-link__text-decoration__hover, + @_link-color-active: @product-name-link__color__active, + @_link-text-decoration-active: @product-name-link__text-decoration__active ); } } @@ -613,11 +614,11 @@ & when (@media-common = true) { .abs-navigation-icon { .lib-icon-font( - @_icon-font-content: @icon-down, - @_icon-font-size: 34px, - @_icon-font-line-height: 1.2, - @_icon-font-position: after, - @_icon-font-display: block + @_icon-font-content: @icon-down, + @_icon-font-size: 34px, + @_icon-font-line-height: 1.2, + @_icon-font-position: after, + @_icon-font-display: block ); &:after { @@ -635,8 +636,8 @@ & when (@media-common = true) { .abs-split-button { .lib-dropdown-split( - @_options-selector : ~'.items', - @_dropdown-split-button-border-radius-fix: true + @_options-selector : ~'.items', + @_dropdown-split-button-border-radius-fix: true ); vertical-align: middle; } @@ -654,13 +655,13 @@ .abs-actions-addto-gridlist { .lib-icon-font( - @_icon-font-content: '', - @_icon-font-size: 29px, - @_icon-font-color: @addto-color, - @_icon-font-color-hover: @addto-hover-color, - @_icon-font-text-hide: true, - @_icon-font-vertical-align: middle, - @_icon-font-line-height: 24px + @_icon-font-content: '', + @_icon-font-size: 29px, + @_icon-font-color: @addto-color, + @_icon-font-color-hover: @addto-hover-color, + @_icon-font-text-hide: true, + @_icon-font-vertical-align: middle, + @_icon-font-line-height: 24px ); } } @@ -762,11 +763,11 @@ padding-right: 12px; position: relative; .lib-icon-font( - @icon-down, - @_icon-font-size: 26px, - @_icon-font-line-height: 10px, - @_icon-font-margin: 3px 0 0 0, - @_icon-font-position: after + @icon-down, + @_icon-font-size: 26px, + @_icon-font-line-height: 10px, + @_icon-font-margin: 3px 0 0 0, + @_icon-font-position: after ); &:after { @@ -777,16 +778,16 @@ &-expanded { .lib-icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after + @_icon-font-content: @icon-up, + @_icon-font-position: after ); } } .abs-tax-total-expanded { .lib-icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after + @_icon-font-content: @icon-up, + @_icon-font-position: after ); } } @@ -867,10 +868,10 @@ & when (@media-common = true) { .abs-icon-add { .lib-icon-font( - @_icon-font-content: @icon-expand, - @_icon-font-size: 10px, - @_icon-font-line-height: 10px, - @_icon-font-vertical-align: middle + @_icon-font-content: @icon-expand, + @_icon-font-size: 10px, + @_icon-font-line-height: 10px, + @_icon-font-vertical-align: middle ); } } @@ -878,12 +879,12 @@ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { .abs-icon-add-mobile { .lib-icon-font( - @_icon-font-content: @icon-expand, - @_icon-font-size: 10px, - @_icon-font-line-height: 10px, - @_icon-font-vertical-align: middle, - @_icon-font-margin: 0 5px 0 0, - @_icon-font-display: block + @_icon-font-content: @icon-expand, + @_icon-font-size: 10px, + @_icon-font-line-height: 10px, + @_icon-font-vertical-align: middle, + @_icon-font-margin: 0 5px 0 0, + @_icon-font-display: block ); } } @@ -924,11 +925,11 @@ position: relative; .lib-icon-font( - @_icon-font-content: @icon-down, - @_icon-font-size: 28px, - @_icon-font-text-hide: false, - @_icon-font-position: after, - @_icon-font-display: block + @_icon-font-content: @icon-down, + @_icon-font-size: 28px, + @_icon-font-text-hide: false, + @_icon-font-position: after, + @_icon-font-display: block ); &:after { @@ -1068,12 +1069,12 @@ font-weight: @font-weight__bold; .lib-link-as-button(); .lib-button( - @_button-padding: 7px 15px 7px 0, - @_button-icon-use: true, - @_button-font-content: @icon-prev, - @_button-icon-font-size: 32px, - @_button-icon-font-line-height: 16px, - @_button-icon-font-position: before + @_button-padding: 7px 15px 7px 0, + @_button-icon-use: true, + @_button-font-content: @icon-prev, + @_button-icon-font-size: 32px, + @_button-icon-font-line-height: 16px, + @_button-icon-font-position: before ); &:active { @@ -1083,9 +1084,9 @@ &.update { .lib-button-icon( - @icon-update, - @_icon-font-size: 32px, - @_icon-font-line-height: 16px + @icon-update, + @_icon-font-size: 32px, + @_icon-font-line-height: 16px ); padding-left: @indent__xs; } @@ -1160,7 +1161,7 @@ & when (@media-common = true) { .abs-field-date-input { - .lib-css(margin-right, @indent__s); + margin-right: @indent__s; width: calc(~'100% -' @icon-calendar__font-size + @indent__s); } } @@ -1175,7 +1176,7 @@ position: relative; input { - .lib-css(margin-right, @indent__s); + margin-right: @indent__s; width: calc(~'100% -' @checkout-tooltip-icon__font-size + @indent__s + @indent__xs); } } @@ -1193,12 +1194,12 @@ &:before, &:after { .lib-arrow( - @_position: top, - @_size: @checkout-tooltip-icon-arrow__font-size, - @_color: @checkout-tooltip-content__background-color + @_position: top, + @_size: @checkout-tooltip-icon-arrow__font-size, + @_color: @checkout-tooltip-content__background-color ); .lib-css(margin-top, @checkout-tooltip-icon-arrow__left); - .lib-css(right, @indent__s); + right: @indent__s; left: auto; top: 0; } @@ -1234,11 +1235,11 @@ .lib-css(border-bottom, @checkout-step-title__border); .lib-css(padding-bottom, @checkout-step-title__padding); .lib-typography( - @_font-size: @checkout-step-title__font-size, - @_font-weight: @checkout-step-title__font-weight, - @_font-family: false, - @_font-style: false, - @_line-height: false + @_font-size: @checkout-step-title__font-size, + @_font-weight: @checkout-step-title__font-weight, + @_font-family: false, + @_font-style: false, + @_line-height: false ); } } @@ -1299,11 +1300,11 @@ .amount .price { .lib-icon-font( - @icon-down, - @_icon-font-size: 30px, - @_icon-font-text-hide: true, - @_icon-font-position: after, - @_icon-font-display: block + @icon-down, + @_icon-font-size: 30px, + @_icon-font-text-hide: true, + @_icon-font-position: after, + @_icon-font-display: block ); padding-right: @indent__m; position: relative; @@ -1323,8 +1324,8 @@ .amount .price { .lib-icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after + @_icon-font-content: @icon-up, + @_icon-font-position: after ); } } @@ -1332,7 +1333,7 @@ &-details { display: none; - .lib-css(border-bottom, @border-width__base solid @border-color__base); + border-bottom: @border-width__base solid @border-color__base; &.shown { display: table-row; @@ -1357,10 +1358,10 @@ cursor: pointer; font-weight: @font-weight__semibold; .lib-icon-font( - @_icon-font-content: @icon-down, - @_icon-font-size: 30px, - @_icon-font-position: after, - @_icon-font-display: block + @_icon-font-content: @icon-down, + @_icon-font-size: 30px, + @_icon-font-position: after, + @_icon-font-display: block ); margin-bottom: 0; overflow: hidden; @@ -1388,8 +1389,8 @@ &.active { > .title { .lib-icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after + @_icon-font-content: @icon-up, + @_icon-font-position: after ); } From 8485195aaee3d02e0d4c3a5a5ed5694dab6ff3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Tue, 30 Oct 2018 22:11:16 +0200 Subject: [PATCH 0377/1158] Update _toolbar.less --- .../web/css/source/module/_toolbar.less | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less index aceccb06d47f7..2468d2a3104e4 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less @@ -4,14 +4,17 @@ // */ // -// Common -// _____________________________________________ +// Variables +// --------------------------------------------- @toolbar-mode-icon-font-size: 24px; @toolbar-element-background: @panel__background-color; -& when (@media-common = true) { +// +// Common +// _____________________________________________ +& when (@media-common = true) { .page-products { .columns { position: relative; @@ -72,12 +75,12 @@ .sorter-action { vertical-align: top; .lib-icon-font( - @icon-arrow-up, - @_icon-font-size: 28px, - @_icon-font-line-height: 32px, - @_icon-font-color: @header-icons-color, - @_icon-font-color-hover: @header-icons-color-hover, - @_icon-font-text-hide: true + @icon-arrow-up, + @_icon-font-size: 28px, + @_icon-font-line-height: 32px, + @_icon-font-color: @header-icons-color, + @_icon-font-color-hover: @header-icons-color-hover, + @_icon-font-text-hide: true ); } @@ -99,7 +102,7 @@ } .limiter-label { - font-weight: 400; + font-weight: @font-weight__regular; } .limiter { @@ -176,11 +179,11 @@ } .lib-icon-font( - @icon-grid, - @_icon-font-size: @toolbar-mode-icon-font-size, - @_icon-font-text-hide: true, - @_icon-font-color: @text__color__muted, - @_icon-font-color-hover: @text__color__muted + @icon-grid, + @_icon-font-size: @toolbar-mode-icon-font-size, + @_icon-font-text-hide: true, + @_icon-font-color: @text__color__muted, + @_icon-font-color-hover: @text__color__muted ); } From 54f4802d5a9ef58418e395e8d12ab4931907d6eb Mon Sep 17 00:00:00 2001 From: larsroettig Date: Tue, 30 Oct 2018 21:32:40 +0100 Subject: [PATCH 0378/1158] #18956 Fixes for set root_category_id --- .../Magento/Store/Model/Config/Importer/Processor/Create.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php index 513ba04802985..3142955ac5988 100644 --- a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php +++ b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php @@ -177,8 +177,8 @@ private function createGroups(array $items, array $data) ); $group = $this->groupFactory->create(); - $group->setData($groupData); $group->setRootCategoryId(0); + $group->setData($groupData); $group->getResource()->save($group); $group->getResource()->addCommitCallback(function () use ($data, $group, $website) { From bbc75173ae7ae2b32139714de7616b07da51c845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Wed, 31 Oct 2018 09:06:08 +0200 Subject: [PATCH 0379/1158] Code clean up --- .../Magento_Checkout/web/css/source/module/_minicart.less | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less index 2219db1cf694d..d7ff3ba1e5732 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less @@ -125,7 +125,7 @@ float: right; .block-minicart { - padding: 25px @minicart__padding-horizontal; + .lib-css(padding, 25px @minicart__padding-horizontal); .block-title { display: none; @@ -205,8 +205,8 @@ } .minicart-items-wrapper { - border: 1px solid @minicart__border-color; - margin: 0 -@minicart__padding-horizontal; + .lib-css(border, 1px solid @minicart__border-color); + .lib-css(margin, 0 -@minicart__padding-horizontal); border-left: 0; border-right: 0; overflow-x: auto; @@ -220,7 +220,7 @@ padding: @indent__base 0; &:not(:first-child) { - border-top: 1px solid @minicart__border-color; + .lib-css(border-top, 1px solid @minicart__border-color); } &:first-child { From 0d5150ff3edd3544161841076d1f70a7ad8c72b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Wed, 31 Oct 2018 09:09:38 +0200 Subject: [PATCH 0380/1158] Code clean up --- app/design/frontend/Magento/blank/web/css/source/_extends.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less index 4b328ab1015ed..5f24c0db8cc88 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_extends.less +++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less @@ -1332,8 +1332,8 @@ } &-details { + .lib-css(border-bottom, @border-width__base solid @border-color__base); display: none; - border-bottom: @border-width__base solid @border-color__base; &.shown { display: table-row; From 93af83615f677eaa17eab74f9828fb2f8a7db0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karla=20Saarem=C3=A4e?= Date: Wed, 31 Oct 2018 09:13:02 +0200 Subject: [PATCH 0381/1158] code clean up --- .../Magento_Checkout/web/css/source/module/_minicart.less | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less index 14db9dd868e00..17fbdc8ba495b 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less @@ -128,7 +128,7 @@ float: right; .block-minicart { - padding: 25px @minicart__padding-horizontal; + .lib-css(padding, 25px @minicart__padding-horizontal); .block-title { display: none; @@ -216,8 +216,8 @@ } .minicart-items-wrapper { - border: 1px solid @minicart__border-color; - margin: 0 -@minicart__padding-horizontal; + .lib-css(border, 1px solid @minicart__border-color); + .lib-css(margin, 0 -@minicart__padding-horizontal); border-left: 0; border-right: 0; overflow-x: auto; @@ -231,7 +231,7 @@ padding: @indent__base 0; &:not(:first-child) { - border-top: 1px solid @minicart__border-color; + .lib-css(border-top, 1px solid @minicart__border-color); } &:first-child { From b135ec9c010f6a06649da1a30bf7778a52988a03 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 31 Oct 2018 10:43:01 +0300 Subject: [PATCH 0382/1158] MAGETWO-91609: Problems with operator more/less in the "catalog Products List" widget - Fix unit test --- .../Test/Unit/Model/Condition/Sql/BuilderTest.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php index 5d18ccef17e54..13bba8a6a28ab 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php @@ -119,13 +119,12 @@ public function testAttachConditionAsHtmlToCollection() \Magento\Eav\Model\Entity\Collection\AbstractCollection::class, [ 'getResource', - 'getSelect', - 'getStoreId', - 'getDefaultStoreId', + 'getSelect' ] ); - $combine = $this->createPartialMock(\Magento\Rule\Model\Condition\Combine::class, + $combine = $this->createPartialMock( + \Magento\Rule\Model\Condition\Combine::class, [ 'getConditions', 'getValue', @@ -153,14 +152,6 @@ public function testAttachConditionAsHtmlToCollection() ->method('getResource') ->will($this->returnValue($resource)); - $collection->expects($this->once()) - ->method('getStoreId') - ->willReturn(1); - - $collection->expects($this->once()) - ->method('getDefaultStoreId') - ->willReturn(1); - $resource->expects($this->once()) ->method('getConnection') ->will($this->returnValue($connection)); From 8641218ebe978623fb1aa731544b76be99003448 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov Date: Wed, 31 Oct 2018 11:09:20 +0200 Subject: [PATCH 0383/1158] MAGETWO-95299: Ability to upload PDP images without compression and downsizing --- .../view/adminhtml/templates/browser/content/uploader.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml index df0a74c48ac23..414d42cb45382 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml @@ -19,9 +19,9 @@ foreach ($filters as $media_type) { $resizeConfig = $block->getImageUploadConfigData()->getIsResizeEnabled() ? "{action: 'resize', maxWidth: " - . $block->getImageUploadMaxWidth() + . $block->escapeHtml($block->getImageUploadMaxWidth()) . ", maxHeight: " - . $block->getImageUploadMaxHeight() + . $block->escapeHtml($block->getImageUploadMaxHeight()) . "}" : "{action: 'resize'}"; ?> @@ -153,7 +153,7 @@ require([ fileTypes: /^image\/(gif|jpeg|png)$/, maxFileSize: getFileSizeService()->getMaxFileSize() ?> * 10 }, - escapeHtml($resizeConfig) ?>, + , { action: 'save' }] From 7fd52e7ea8f7c7f77702d1b7a4665e715eee1ac3 Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi Date: Wed, 31 Oct 2018 11:31:19 +0200 Subject: [PATCH 0384/1158] Remove all possible native php functions & use framework components --- .../Model/Product/Gallery/Processor.php | 33 ++++++++++++------- composer.json | 1 - 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index 225c502830695..048ad55985b72 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -57,25 +57,34 @@ class Processor */ protected $resourceModel; + /** + * @var \Magento\Framework\File\Mime + */ + protected $mime; + /** * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository * @param \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDb * @param \Magento\Catalog\Model\Product\Media\Config $mediaConfig * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel + * @param \Magento\Framework\File\Mime $mime + * @throws \Magento\Framework\Exception\FileSystemException */ public function __construct( \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository, \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDb, \Magento\Catalog\Model\Product\Media\Config $mediaConfig, \Magento\Framework\Filesystem $filesystem, - \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel + \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel, + \Magento\Framework\File\Mime $mime ) { $this->attributeRepository = $attributeRepository; $this->fileStorageDb = $fileStorageDb; $this->mediaConfig = $mediaConfig; $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); $this->resourceModel = $resourceModel; + $this->mime = $mime; } /** @@ -186,10 +195,10 @@ public function addImage( $position = 0; $absoluteFilePath = $this->mediaDirectory->getAbsolutePath($file); - $imageMimeType = mime_content_type($absoluteFilePath); - $imageContent = file_get_contents($absoluteFilePath); + $imageMimeType = $this->mime->getMimeType($absoluteFilePath); + $imageContent = $this->mediaDirectory->readFile($absoluteFilePath); $imageBase64 = base64_encode($imageContent); - $imageName = pathinfo($destinationFile, PATHINFO_FILENAME); + $imageName = $pathinfo['filename']; if (!is_array($mediaGalleryData)) { $mediaGalleryData = ['images' => []]; @@ -203,17 +212,17 @@ public function addImage( $position++; $mediaGalleryData['images'][] = [ - 'file' => $fileName, - 'position' => $position, - 'label' => '', - 'disabled' => (int)$exclude, + 'file' => $fileName, + 'position' => $position, + 'label' => '', + 'disabled' => (int)$exclude, 'media_type' => 'image', - 'types' => $mediaAttribute, - 'content' => [ + 'types' => $mediaAttribute, + 'content' => [ 'data' => [ - ImageContentInterface::NAME => $imageName, + ImageContentInterface::NAME => $imageName, ImageContentInterface::BASE64_ENCODED_DATA => $imageBase64, - ImageContentInterface::TYPE => $imageMimeType, + ImageContentInterface::TYPE => $imageMimeType, ] ] ]; diff --git a/composer.json b/composer.json index 68bf1f1d8a8b0..e2a646275d98b 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,6 @@ "ext-xsl": "*", "ext-zip": "*", "lib-libxml": "*", - "ext-fileinfo": "*", "braintree/braintree_php": "3.35.0", "colinmollenhour/cache-backend-file": "~1.4.1", "colinmollenhour/cache-backend-redis": "1.10.5", From bdce1b6d8bb67c00312e5d1c1693a0ca7b708a34 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Wed, 31 Oct 2018 13:23:05 +0200 Subject: [PATCH 0385/1158] ENGCOM-1928: Refactoring. --- app/code/Magento/Store/Block/Switcher.php | 20 ------ app/code/Magento/Store/ViewModel/Switcher.php | 72 +++++++++++++++++++ .../frontend/templates/switch/languages.phtml | 2 +- .../Theme/view/frontend/layout/default.xml | 7 +- 4 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 app/code/Magento/Store/ViewModel/Switcher.php diff --git a/app/code/Magento/Store/Block/Switcher.php b/app/code/Magento/Store/Block/Switcher.php index e162a2a0abe16..f15349f11066d 100644 --- a/app/code/Magento/Store/Block/Switcher.php +++ b/app/code/Magento/Store/Block/Switcher.php @@ -265,24 +265,4 @@ public function getTargetStorePostData(Store $store, $data = []) $data ); } - - /** - * Returns target store redirect url. - * - * @param Store $store - * @return string - */ - public function getTargetStoreRedirectUrl(Store $store) - { - return $this->getUrl( - 'stores/store/redirect', - [ - '___store' => $store->getCode(), - '___from_store' => $this->getCurrentStoreCode(), - ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl( - $store->getCurrentUrl(false) - ), - ] - ); - } } diff --git a/app/code/Magento/Store/ViewModel/Switcher.php b/app/code/Magento/Store/ViewModel/Switcher.php new file mode 100644 index 0000000000000..b0d08f064073d --- /dev/null +++ b/app/code/Magento/Store/ViewModel/Switcher.php @@ -0,0 +1,72 @@ +encoder = $encoder; + $this->storeManager = $storeManager; + $this->urlBuilder = $urlBuilder; + } + + /** + * Returns target store redirect url. + * + * @param Store $store + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getTargetStoreRedirectUrl(Store $store): string + { + return $this->urlBuilder->getUrl( + 'stores/store/redirect', + [ + '___store' => $store->getCode(), + '___from_store' => $this->storeManager->getStore()->getCode(), + ActionInterface::PARAM_NAME_URL_ENCODED => $this->encoder->encode( + $store->getCurrentUrl(false) + ), + ] + ); + } +} diff --git a/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml b/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml index 411a1ef3c9a32..a620c2ce71407 100644 --- a/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml +++ b/app/code/Magento/Store/view/frontend/templates/switch/languages.phtml @@ -27,7 +27,7 @@ getStores() as $_lang): ?> getId() != $block->getCurrentStoreId()): ?>
  • - + escapeHtml($_lang->getName()) ?>
  • diff --git a/app/code/Magento/Theme/view/frontend/layout/default.xml b/app/code/Magento/Theme/view/frontend/layout/default.xml index 716341f5a64a4..d6ec289edaa92 100644 --- a/app/code/Magento/Theme/view/frontend/layout/default.xml +++ b/app/code/Magento/Theme/view/frontend/layout/default.xml @@ -39,7 +39,11 @@ Skip to Content - + + + Magento\Store\ViewModel\SwitcherUrlProvider + + header links @@ -82,6 +86,7 @@ nav + Magento\Store\ViewModel\SwitcherUrlProvider From 80da4ea87544caa583ab1c90ed251ea946a8be51 Mon Sep 17 00:00:00 2001 From: prakashpatel07 Date: Wed, 31 Oct 2018 13:38:55 +0000 Subject: [PATCH 0386/1158] Fixed Last Logged-in date when customer authenticate via REST API. --- .../Integration/Model/CustomerTokenService.php | 13 ++++++++++++- .../Test/Unit/Model/CustomerTokenServiceTest.php | 8 +++++++- .../Magento/Integration/etc/webapi_rest/events.xml | 12 ++++++++++++ .../Magento/Integration/etc/webapi_soap/events.xml | 12 ++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Integration/etc/webapi_rest/events.xml create mode 100644 app/code/Magento/Integration/etc/webapi_soap/events.xml diff --git a/app/code/Magento/Integration/Model/CustomerTokenService.php b/app/code/Magento/Integration/Model/CustomerTokenService.php index 3c245804a9f6e..35d0424d3b4fa 100644 --- a/app/code/Magento/Integration/Model/CustomerTokenService.php +++ b/app/code/Magento/Integration/Model/CustomerTokenService.php @@ -14,6 +14,7 @@ use Magento\Integration\Model\ResourceModel\Oauth\Token\CollectionFactory as TokenCollectionFactory; use Magento\Integration\Model\Oauth\Token\RequestThrottler; use Magento\Framework\Exception\AuthenticationException; +use Magento\Framework\Event\ManagerInterface; class CustomerTokenService implements \Magento\Integration\Api\CustomerTokenServiceInterface { @@ -24,6 +25,11 @@ class CustomerTokenService implements \Magento\Integration\Api\CustomerTokenServ */ private $tokenModelFactory; + /** + * @var Magento\Framework\Event\ManagerInterface + */ + private $eventManager; + /** * Customer Account Service * @@ -55,17 +61,21 @@ class CustomerTokenService implements \Magento\Integration\Api\CustomerTokenServ * @param AccountManagementInterface $accountManagement * @param TokenCollectionFactory $tokenModelCollectionFactory * @param \Magento\Integration\Model\CredentialsValidator $validatorHelper + * @param \Magento\Framework\Event\ManagerInterface $eventManager */ public function __construct( TokenModelFactory $tokenModelFactory, AccountManagementInterface $accountManagement, TokenCollectionFactory $tokenModelCollectionFactory, - CredentialsValidator $validatorHelper + CredentialsValidator $validatorHelper, + ManagerInterface $eventManager = null ) { $this->tokenModelFactory = $tokenModelFactory; $this->accountManagement = $accountManagement; $this->tokenModelCollectionFactory = $tokenModelCollectionFactory; $this->validatorHelper = $validatorHelper; + $this->eventManager = $eventManager ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(ManagerInterface::class); } /** @@ -86,6 +96,7 @@ public function createCustomerAccessToken($username, $password) ) ); } + $this->eventManager->dispatch('customer_login', ['customer' => $customerDataObject]); $this->getRequestThrottler()->resetAuthenticationFailuresCount($username, RequestThrottler::USER_TYPE_CUSTOMER); return $this->tokenModelFactory->create()->createCustomerToken($customerDataObject->getId())->getToken(); } diff --git a/app/code/Magento/Integration/Test/Unit/Model/CustomerTokenServiceTest.php b/app/code/Magento/Integration/Test/Unit/Model/CustomerTokenServiceTest.php index 1a7c819343294..1bc7d4247080f 100644 --- a/app/code/Magento/Integration/Test/Unit/Model/CustomerTokenServiceTest.php +++ b/app/code/Magento/Integration/Test/Unit/Model/CustomerTokenServiceTest.php @@ -32,6 +32,9 @@ class CustomerTokenServiceTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Integration\Model\Oauth\Token|\PHPUnit_Framework_MockObject_MockObject */ private $_tokenMock; + /** @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $manager; + protected function setUp() { $this->_tokenFactoryMock = $this->getMockBuilder(\Magento\Integration\Model\Oauth\TokenFactory::class) @@ -67,11 +70,14 @@ protected function setUp() \Magento\Integration\Model\CredentialsValidator::class )->disableOriginalConstructor()->getMock(); + $this->manager = $this->createMock(\Magento\Framework\Event\ManagerInterface::class); + $this->_tokenService = new \Magento\Integration\Model\CustomerTokenService( $this->_tokenFactoryMock, $this->_accountManagementMock, $this->_tokenModelCollectionFactoryMock, - $this->validatorHelperMock + $this->validatorHelperMock, + $this->manager ); } diff --git a/app/code/Magento/Integration/etc/webapi_rest/events.xml b/app/code/Magento/Integration/etc/webapi_rest/events.xml new file mode 100644 index 0000000000000..e978698734277 --- /dev/null +++ b/app/code/Magento/Integration/etc/webapi_rest/events.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/code/Magento/Integration/etc/webapi_soap/events.xml b/app/code/Magento/Integration/etc/webapi_soap/events.xml new file mode 100644 index 0000000000000..e978698734277 --- /dev/null +++ b/app/code/Magento/Integration/etc/webapi_soap/events.xml @@ -0,0 +1,12 @@ + + + + + + + From 02192264fb25a7bf4d61326650d03a7205b0c940 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 31 Oct 2018 16:45:01 +0300 Subject: [PATCH 0387/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static test --- .../view/adminhtml/web/js/grouped-product-grid.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index c1a35cb0afede..f257cb2df729e 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -9,6 +9,7 @@ define([ 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid' ], function (_, registry, dynamicRowsGrid) { 'use strict'; + return dynamicRowsGrid.extend({ /** @@ -191,15 +192,6 @@ define([ return (~~this.currentPage() - 1) * this.pageSize + this.elems().pluck("name").indexOf(data.name); }, - /** - * Returns start index for current page - * - * @return {number} - */ - getStartIndex() { - return (~~this.currentPage() - 1) * this.pageSize; - }, - /** * Return Page Boundary * @@ -214,7 +206,7 @@ define([ * * @return {number} */ - getGlobalMaxPosition() { + getGlobalMaxPosition: function () { return _.max(this.recordData().map(function (r) { return ~~r.position })); From fff8dd3fae6aa65e19d7a5f539123b71d40c7078 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 31 Oct 2018 16:54:25 +0300 Subject: [PATCH 0388/1158] MAGETWO-91609: Problems with operator more/less in the "catalog Products List" widget - Fix static test --- .../Unit/Model/Condition/Sql/BuilderTest.php | 79 ++++--------------- 1 file changed, 17 insertions(+), 62 deletions(-) diff --git a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php index 13bba8a6a28ab..9dcbbd18c4c20 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php @@ -91,30 +91,13 @@ public function testAttachConditionAsHtmlToCollection() ['getOperatorForValidate', 'getMappedSqlField', 'getAttribute', 'getBindArgumentValue'] ); - $abstractCondition->expects($this->once()) - ->method('getMappedSqlField') - ->will($this->returnValue('argument')); - - $abstractCondition->expects($this->once()) - ->method('getOperatorForValidate') - ->will($this->returnValue('>')); - - $abstractCondition->expects($this->at(1)) - ->method('getAttribute') - ->will($this->returnValue('attribute')); - - $abstractCondition->expects($this->at(2)) - ->method('getAttribute') - ->will($this->returnValue('attribute')); - - $abstractCondition->expects($this->once()) - ->method('getBindArgumentValue') - ->will($this->returnValue(10)); - - $conditions = [ - $abstractCondition - ]; + $abstractCondition->expects($this->once())->method('getMappedSqlField')->will($this->returnValue('argument')); + $abstractCondition->expects($this->once())->method('getOperatorForValidate')->will($this->returnValue('>')); + $abstractCondition->expects($this->at(1))->method('getAttribute')->will($this->returnValue('attribute')); + $abstractCondition->expects($this->at(2))->method('getAttribute')->will($this->returnValue('attribute')); + $abstractCondition->expects($this->once())->method('getBindArgumentValue')->will($this->returnValue(10)); + $conditions = [$abstractCondition]; $collection = $this->createPartialMock( \Magento\Eav\Model\Entity\Collection\AbstractCollection::class, [ @@ -122,7 +105,6 @@ public function testAttachConditionAsHtmlToCollection() 'getSelect' ] ); - $combine = $this->createPartialMock( \Magento\Rule\Model\Condition\Combine::class, [ @@ -131,10 +113,10 @@ public function testAttachConditionAsHtmlToCollection() 'getAggregator' ] ); + $resource = $this->createPartialMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, ['getConnection']); $select = $this->createPartialMock(\Magento\Framework\DB\Select::class, ['where']); - $select->expects($this->never()) - ->method('where'); + $select->expects($this->never())->method('where'); $connection = $this->getMockForAbstractClass( \Magento\Framework\DB\Adapter\AdapterInterface::class, @@ -143,42 +125,15 @@ public function testAttachConditionAsHtmlToCollection() false ); - $connection->expects($this->once()) - ->method('quoteInto') - ->with(' > ?', 10) - ->will($this->returnValue(' > 10')); - - $collection->expects($this->once()) - ->method('getResource') - ->will($this->returnValue($resource)); - - $resource->expects($this->once()) - ->method('getConnection') - ->will($this->returnValue($connection)); - - $combine->expects($this->once()) - ->method('getValue') - ->willReturn('attribute'); - - $combine->expects($this->once()) - ->method('getAggregator') - ->willReturn(' AND '); - - $combine->expects($this->at(0)) - ->method('getConditions') - ->will($this->returnValue($conditions)); - - $combine->expects($this->at(1)) - ->method('getConditions') - ->will($this->returnValue($conditions)); - - $combine->expects($this->at(2)) - ->method('getConditions') - ->will($this->returnValue($conditions)); - - $combine->expects($this->at(3)) - ->method('getConditions') - ->will($this->returnValue($conditions)); + $connection->expects($this->once())->method('quoteInto')->with(' > ?', 10)->will($this->returnValue(' > 10')); + $collection->expects($this->once())->method('getResource')->will($this->returnValue($resource)); + $resource->expects($this->once())->method('getConnection')->will($this->returnValue($connection)); + $combine->expects($this->once())->method('getValue')->willReturn('attribute'); + $combine->expects($this->once())->method('getAggregator')->willReturn(' AND '); + $combine->expects($this->at(0))->method('getConditions')->will($this->returnValue($conditions)); + $combine->expects($this->at(1))->method('getConditions')->will($this->returnValue($conditions)); + $combine->expects($this->at(2))->method('getConditions')->will($this->returnValue($conditions)); + $combine->expects($this->at(3))->method('getConditions')->will($this->returnValue($conditions)); $this->_builder->attachConditionToCollection($collection, $combine); } From 867fc399768238d7cd084f34295bc750d93fb671 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 31 Oct 2018 17:05:51 +0300 Subject: [PATCH 0389/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Fix static test --- .../Magento/Authorizenet/Model/Directpost.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Authorizenet/Model/Directpost.php b/app/code/Magento/Authorizenet/Model/Directpost.php index c59c44622b8cb..a409251aa76ef 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost.php +++ b/app/code/Magento/Authorizenet/Model/Directpost.php @@ -371,8 +371,7 @@ public function void(\Magento\Payment\Model\InfoInterface $payment) } /** - * Refund the amount - * Need to decode last 4 digits for request. + * Refund the amount need to decode last 4 digits for request. * * @param \Magento\Framework\DataObject|\Magento\Payment\Model\InfoInterface $payment * @param float $amount @@ -630,7 +629,7 @@ protected function fillPaymentByResponse(\Magento\Framework\DataObject $payment) $additionalInformationKeys = explode(',', $this->getValue('paymentInfoKeys')); foreach ($additionalInformationKeys as $paymentInfoKey) { $paymentInfoValue = $response->getDataByKey($paymentInfoKey); - if($paymentInfoValue !== null) { + if ($paymentInfoValue !== null) { $payment->setAdditionalInformation($paymentInfoKey, $paymentInfoValue); } } @@ -690,6 +689,7 @@ protected function matchAmount($amount) /** * Operate with order using information from Authorize.net. + * * Authorize order or authorize and capture it. * * @param \Magento\Sales\Model\Order $order @@ -866,7 +866,7 @@ public function getConfigInterface() * Getter for specified value according to set payment method code * * @param mixed $key - * @param null $storeId + * @param int|string|null|\Magento\Store\Model\Store $storeId * @return mixed */ public function getValue($key, $storeId = null) @@ -930,6 +930,8 @@ public function fetchTransactionInfo(\Magento\Payment\Model\InfoInterface $payme } /** + * Add statuc comment on update. + * * @param \Magento\Sales\Model\Order\Payment $payment * @param \Magento\Framework\DataObject $response * @param string $transactionId @@ -1004,8 +1006,9 @@ protected function getTransactionResponse($transactionId) } /** - * @return \Psr\Log\LoggerInterface + * Get psr logger. * + * @return \Psr\Log\LoggerInterface * @deprecated 100.1.0 */ private function getPsrLogger() @@ -1046,7 +1049,9 @@ private function getOrderIncrementId(): string } /** - * Checks if filter action is Report Only. Transactions that trigger this filter are processed as normal, + * Checks if filter action is Report Only. + * + * Transactions that trigger this filter are processed as normal, * but are also reported in the Merchant Interface as triggering this filter. * * @param string $fdsFilterAction From 9f568fb21b4c211c85fcf675fb504d2c1971be4d Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin Date: Wed, 31 Oct 2018 16:15:03 +0200 Subject: [PATCH 0390/1158] MAGETWO-96007: Customer address issue when creating or updating via API --- .../ResourceModel/CustomerRepository.php | 99 ++++++++++--------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 43ae2db0c2163..a053eee5cd09b 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -8,69 +8,80 @@ use Magento\Customer\Api\CustomerMetadataInterface; use Magento\Customer\Api\Data\CustomerInterface; -use Magento\Customer\Model\Delegation\Data\NewOperation; +use Magento\Customer\Api\Data\CustomerSearchResultsInterfaceFactory; +use Magento\Framework\Api\ExtensibleDataObjectConverter; +use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface; +use Magento\Customer\Model\CustomerFactory; +use Magento\Customer\Model\CustomerRegistry; +use Magento\Customer\Model\Data\CustomerSecureFactory; use Magento\Customer\Model\Customer\NotificationStorage; +use Magento\Customer\Model\Delegation\Data\NewOperation; +use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\Api\ImageProcessorInterface; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\Search\FilterGroup; +use Magento\Framework\Event\ManagerInterface; use Magento\Customer\Model\Delegation\Storage as DelegatedStorage; use Magento\Framework\App\ObjectManager; +use Magento\Store\Model\StoreManagerInterface; /** * Customer repository. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.TooManyFields) */ -class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInterface +class CustomerRepository implements CustomerRepositoryInterface { /** - * @var \Magento\Customer\Model\CustomerFactory + * @var CustomerFactory */ protected $customerFactory; /** - * @var \Magento\Customer\Model\Data\CustomerSecureFactory + * @var CustomerSecureFactory */ protected $customerSecureFactory; /** - * @var \Magento\Customer\Model\CustomerRegistry + * @var CustomerRegistry */ protected $customerRegistry; /** - * @var \Magento\Customer\Model\ResourceModel\AddressRepository + * @var AddressRepository */ protected $addressRepository; /** - * @var \Magento\Customer\Model\ResourceModel\Customer + * @var Customer */ protected $customerResourceModel; /** - * @var \Magento\Customer\Api\CustomerMetadataInterface + * @var CustomerMetadataInterface */ protected $customerMetadata; /** - * @var \Magento\Customer\Api\Data\CustomerSearchResultsInterfaceFactory + * @var CustomerSearchResultsInterfaceFactory */ protected $searchResultsFactory; /** - * @var \Magento\Framework\Event\ManagerInterface + * @var ManagerInterface */ protected $eventManager; /** - * @var \Magento\Store\Model\StoreManagerInterface + * @var StoreManagerInterface */ protected $storeManager; /** - * @var \Magento\Framework\Api\ExtensibleDataObjectConverter + * @var ExtensibleDataObjectConverter */ protected $extensibleDataObjectConverter; @@ -85,7 +96,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte protected $imageProcessor; /** - * @var \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface + * @var JoinProcessorInterface */ protected $extensionAttributesJoinProcessor; @@ -105,38 +116,38 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte private $delegatedStorage; /** - * @param \Magento\Customer\Model\CustomerFactory $customerFactory - * @param \Magento\Customer\Model\Data\CustomerSecureFactory $customerSecureFactory - * @param \Magento\Customer\Model\CustomerRegistry $customerRegistry - * @param \Magento\Customer\Model\ResourceModel\AddressRepository $addressRepository - * @param \Magento\Customer\Model\ResourceModel\Customer $customerResourceModel - * @param \Magento\Customer\Api\CustomerMetadataInterface $customerMetadata - * @param \Magento\Customer\Api\Data\CustomerSearchResultsInterfaceFactory $searchResultsFactory - * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Store\Model\StoreManagerInterface $storeManager - * @param \Magento\Framework\Api\ExtensibleDataObjectConverter $extensibleDataObjectConverter + * @param CustomerFactory $customerFactory + * @param CustomerSecureFactory $customerSecureFactory + * @param CustomerRegistry $customerRegistry + * @param AddressRepository $addressRepository + * @param Customer $customerResourceModel + * @param CustomerMetadataInterface $customerMetadata + * @param CustomerSearchResultsInterfaceFactory $searchResultsFactory + * @param ManagerInterface $eventManager + * @param StoreManagerInterface $storeManager + * @param ExtensibleDataObjectConverter $extensibleDataObjectConverter * @param DataObjectHelper $dataObjectHelper * @param ImageProcessorInterface $imageProcessor - * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor + * @param JoinProcessorInterface $extensionAttributesJoinProcessor * @param CollectionProcessorInterface $collectionProcessor * @param NotificationStorage $notificationStorage * @param DelegatedStorage|null $delegatedStorage * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Customer\Model\CustomerFactory $customerFactory, - \Magento\Customer\Model\Data\CustomerSecureFactory $customerSecureFactory, - \Magento\Customer\Model\CustomerRegistry $customerRegistry, - \Magento\Customer\Model\ResourceModel\AddressRepository $addressRepository, - \Magento\Customer\Model\ResourceModel\Customer $customerResourceModel, - \Magento\Customer\Api\CustomerMetadataInterface $customerMetadata, - \Magento\Customer\Api\Data\CustomerSearchResultsInterfaceFactory $searchResultsFactory, - \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Framework\Api\ExtensibleDataObjectConverter $extensibleDataObjectConverter, + CustomerFactory $customerFactory, + CustomerSecureFactory $customerSecureFactory, + CustomerRegistry $customerRegistry, + AddressRepository $addressRepository, + Customer $customerResourceModel, + CustomerMetadataInterface $customerMetadata, + CustomerSearchResultsInterfaceFactory $searchResultsFactory, + ManagerInterface $eventManager, + StoreManagerInterface $storeManager, + ExtensibleDataObjectConverter $extensibleDataObjectConverter, DataObjectHelper $dataObjectHelper, ImageProcessorInterface $imageProcessor, - \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor, + JoinProcessorInterface $extensionAttributesJoinProcessor, CollectionProcessorInterface $collectionProcessor, NotificationStorage $notificationStorage, DelegatedStorage $delegatedStorage = null @@ -156,8 +167,7 @@ public function __construct( $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor; $this->collectionProcessor = $collectionProcessor; $this->notificationStorage = $notificationStorage; - $this->delegatedStorage = $delegatedStorage - ?? ObjectManager::getInstance()->get(DelegatedStorage::class); + $this->delegatedStorage = $delegatedStorage ?? ObjectManager::getInstance()->get(DelegatedStorage::class); } /** @@ -200,13 +210,13 @@ public function save(CustomerInterface $customer, $passwordHash = null) $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } - if (!array_key_exists('default_billing', $customerArr) + if (!array_key_exists('addresses', $customerArr) && null !== $prevCustomerDataArr && array_key_exists('default_billing', $prevCustomerDataArr) ) { $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); } - if (!array_key_exists('default_shipping', $customerArr) + if (!array_key_exists('addresses', $customerArr) && null !== $prevCustomerDataArr && array_key_exists('default_shipping', $prevCustomerDataArr) ) { @@ -371,15 +381,12 @@ public function deleteById($customerId) * Helper function that adds a FilterGroup to the collection. * * @deprecated 100.2.0 - * @param \Magento\Framework\Api\Search\FilterGroup $filterGroup - * @param \Magento\Customer\Model\ResourceModel\Customer\Collection $collection + * @param FilterGroup $filterGroup + * @param Collection $collection * @return void - * @throws \Magento\Framework\Exception\InputException */ - protected function addFilterGroupToCollection( - \Magento\Framework\Api\Search\FilterGroup $filterGroup, - \Magento\Customer\Model\ResourceModel\Customer\Collection $collection - ) { + protected function addFilterGroupToCollection(FilterGroup $filterGroup, Collection $collection) + { $fields = []; foreach ($filterGroup->getFilters() as $filter) { $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq'; From 24b690fbc3610641c674f88893fd01b0aab70118 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 31 Oct 2018 17:19:46 +0300 Subject: [PATCH 0391/1158] MAGETWO-91649: Magento ignore store-level url_key of child category in URL rewrite process for global scope - Fix static test --- .../Observer/CategoryUrlPathAutogeneratorObserver.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index 5c7a8b16a666e..d692918aff6a6 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -14,6 +14,9 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Store\Model\Store; +/** + * Class for set or update url path. + */ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface { /** @@ -55,6 +58,8 @@ public function __construct( } /** + * Method for update/set url path. + * * @param \Magento\Framework\Event\Observer $observer * @return void * @throws \Magento\Framework\Exception\LocalizedException @@ -81,6 +86,8 @@ public function execute(\Magento\Framework\Event\Observer $observer) } /** + * Update url path for children category. + * * @param Category $category * @return void */ @@ -121,6 +128,8 @@ protected function isGlobalScope($storeId) } /** + * Update url path for category. + * * @param Category $category * @return void */ From 7daec41bcf5451b2ca7cb11b3e4784a9049f090c Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 31 Oct 2018 09:39:34 -0500 Subject: [PATCH 0392/1158] MAGETWO-94313: Random test failures on jenkins - unskip Magento\Reports\Test\TestCase\ProductsInCartReportEntityTest --- .../Reports/Test/TestCase/ProductsInCartReportEntityTest.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.xml index fd0d169967161..e13d31342dba1 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.xml @@ -8,14 +8,12 @@ - MQE-1160 default 1 0 - MQE-1160 default 2 1 From 07c2d7a3447e6c8079e02e331777e00ba835e6ed Mon Sep 17 00:00:00 2001 From: Dmytro Drozd Date: Wed, 31 Oct 2018 16:53:51 +0200 Subject: [PATCH 0393/1158] MAGETWO-96026: Create MFTF test for MAGETWO-93973 --- .../Test/Mftf/Page/AdminProductCreatePage.xml | 1 + ...minProductFormAdvancedInventorySection.xml | 37 +++++++++ .../Mftf/Section/AdminProductFormSection.xml | 1 + ...IncrementsWorkWithDecimalinventoryTest.xml | 75 +++++++++++++++++++ .../Section/StorefrontQuickSearchSection.xml | 2 +- 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml index fc776b49ba213..b3ed3f478f810 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml @@ -17,5 +17,6 @@
    +
    diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml new file mode 100644 index 0000000000000..e1272899b78ab --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml @@ -0,0 +1,37 @@ + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml index 03df9d2a88107..9ec0dbf9f262c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml @@ -28,6 +28,7 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml new file mode 100644 index 0000000000000..7a774c585c9cd --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml @@ -0,0 +1,75 @@ + + + + + + + <description value="Tiered pricing and quantity increments work with decimal inventory"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-91178"/> + <group value="product"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createPreReqCategory"/> + <createData entity="SimpleProduct" stepKey="createPreReqSimpleProduct"> + <requiredEntity createDataKey="createPreReqCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> + <deleteData createDataKey="createPreReqSimpleProduct" stepKey="deletePreReqSimpleProduct"/> + </after> + <!--Step1. Login as admin. Go to Catalog > Products page. Filtering *prod1*. Open *prod1* to edit--> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin" /> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="filterGroupedProductOptions"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <click selector="{{AdminProductGridSection.productGridNameProduct('$$createPreReqSimpleProduct.name$$')}}" + stepKey="clickOpenProductForEdit"/> + <waitForPageLoad time="30" stepKey="waitForProductEditOpen"/> + <!--Step2. Open *Advanced Inventory* pop-up (Click on *Advanced Inventory* link). Set *Qty Uses Decimals* to *Yes*. Click on button *Done* --> + <click selector="{{AdminProductFormSection.advancedInventoryLink}}" stepKey="clickOnAdvancedInventoryLink"/> + <scrollTo selector="{{AdminProductFormAdvancedInventorySection.qtyUsesDecimals}}" stepKey="scrollToQtyUsesDecimalsDropBox"/> + <click selector="{{AdminProductFormAdvancedInventorySection.qtyUsesDecimals}}" stepKey="clickOnQtyUsesDecimalsDropBox"/> + <click selector="{{AdminProductFormAdvancedInventorySection.qtyUsesDecimalsOptions('1')}}" stepKey="chooseYesOnQtyUsesDecimalsDropBox"/> + <click selector="{{AdminProductFormAdvancedInventorySection.doneButton}}" stepKey="clickOnDoneButton"/> + <!--Step3. Open *Advanced Pricing* pop-up (Click on *Advanced Pricing* link). Click on *Add* button. Fill *0.5* in *Quantity*--> + <scrollTo selector="{{AdminProductFormSection.productName}}" stepKey="scrollToProductName"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingLink1"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="clickOnCustomerGroupPriceAddButton"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" userInput="0.5" stepKey="fillProductTierPriceQty"/> + <!--Step4. Close *Advanced Pricing* (Click on button *Done*). Save *prod1* (Click on button *Save*)--> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickOnDoneButton2"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickOnSaveButton"/> + + <!--The code should be uncommented after fix MAGETWO-96016--> + <!--<click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingLink2"/>--> + <!--<seeInField userInput="0.5" selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" stepKey="seeInField1"/>--> + <!--<click selector="{{AdminProductFormAdvancedPricingSection.advancedPricingCloseButton}}" stepKey="clickOnCloseButton"/>--> + + <!--Step5. Open *Advanced Inventory* pop-up. Set *Enable Qty Increments* to *Yes*. Fill *.5* in *Qty Increments*--> + <click selector="{{AdminProductFormSection.advancedInventoryLink}}" stepKey="clickOnAdvancedInventoryLink2"/> + <scrollTo selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrements}}" stepKey="scrollToEnableQtyIncrements"/> + <click selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrementsUseConfigSettings}}" stepKey="clickOnEnableQtyIncrementsUseConfigSettingsCheckbox"/> + <click selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrements}}" stepKey="clickOnEnableQtyIncrements"/> + <click selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrementsOptions(('1'))}}" stepKey="chooseYesOnEnableQtyIncrements"/> + <click selector="{{AdminProductFormAdvancedInventorySection.qtyIncrementsUseConfigSettings}}" stepKey="clickOnQtyIncrementsUseConfigSettings"/> + <fillField selector="{{AdminProductFormAdvancedInventorySection.qtyIncrements}}" userInput=".5" stepKey="fillQtyIncrements"/> + <!--Step6. Close *Advanced Inventory* (Click on button *Done*). Save *prod1* (Click on button *Save*) --> + <click selector="{{AdminProductFormAdvancedInventorySection.doneButton}}" stepKey="clickOnDoneButton3"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickOnSaveButton2"/> + <!--Step7. Open *Customer view* (Go to *Store Front*). Open *prod1* page (Find via search and click on product name) --> + <amOnPage url="{{StorefrontHomePage.url}}$$createPreReqSimpleProduct.custom_attributes[url_key]$$.html" stepKey="amOnProductPage"/> + <!--Step8. Fill *1.5* in *Qty*. Click on button *Add to Cart*--> + <fillField selector="{{StorefrontProductPageSection.qtyInput}}" userInput="1.5" stepKey="fillQty"/> + <click selector="{{StorefrontProductPageSection.addToCartBtn}}" stepKey="clickOnAddToCart"/> + <waitForElementVisible selector="{{StorefrontProductPageSection.successMsg}}" time="30" stepKey="waitForProductAdded"/> + <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createPreReqSimpleProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> + <!--Step9. Click on *Cart* icon. Click on *View and Edit Cart* link. Change *Qty* value to *5.5*--> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToShoppingCartFromMinicart"/> + <fillField selector="{{CheckoutCartProductSection.ProductQuantityByName(('$$createPreReqSimpleProduct.name$$'))}}" userInput="5.5" stepKey="fillQty2"/> + <click selector="{{CheckoutCartProductSection.updateShoppingCartButton}}" stepKey="clickOnUpdateShoppingCartButton"/> + <seeInField userInput="5.5" selector="{{CheckoutCartProductSection.ProductQuantityByName(('$$createPreReqSimpleProduct.name$$'))}}" stepKey="seeInField2"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml index 2b08e9b4b85ec..6baa3ff54fca0 100644 --- a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml +++ b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml @@ -8,7 +8,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="StorefrontQuickSearchSection"> + <section name="StorefrontQuickSearchSection">/ <element name="searchPhrase" type="input" selector="#search"/> <element name="searchButton" type="button" selector="button.action.search" timeout="30"/> </section> From 3e94424757aa1b8ad2febc89617f5b199057b8ec Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Wed, 31 Oct 2018 17:12:26 +0200 Subject: [PATCH 0394/1158] MAGETWO-96026: Create MFTF test for MAGETWO-93973 --- .../AdminProductFormAdvancedInventorySection.xml | 12 ------------ .../Mftf/Section/StorefrontQuickSearchSection.xml | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml index e1272899b78ab..0314534dcddfb 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedInventorySection.xml @@ -9,17 +9,6 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminProductFormAdvancedInventorySection"> - <!--<element name="customerGroupPriceAddButton" type="button" selector="[data-action='add_new_row']" timeout="30"/>--> - <!--<element name="customerGroupPriceDeleteButton" type="button" selector="[data-action='remove_row']" timeout="30"/>--> - <!--<element name="advancedPricingCloseButton" type="button" selector=".product_form_product_form_advanced_pricing_modal button.action-close" timeout="30"/>--> - <!--<element name="productTierPriceWebsiteSelect" type="select" selector="[name='product[tier_price][{{var1}}][website_id]']" parameterized="true"/>--> - <!--<element name="productTierPriceCustGroupSelect" type="select" selector="[name='product[tier_price][{{var1}}][cust_group]']" parameterized="true"/>--> - <!--<element name="productTierPriceQtyInput" type="input" selector="[name='product[tier_price][{{var1}}][price_qty]']" parameterized="true"/>--> - <!--<element name="productTierPriceValueTypeSelect" type="select" selector="[name='product[tier_price][{{var1}}][value_type]']" parameterized="true"/>--> - <!--<element name="productTierPriceFixedPriceInput" type="input" selector="[name='product[tier_price][{{var1}}][price]']" parameterized="true"/>--> - <!--<element name="productTierPricePercentageValuePriceInput" type="input" selector="[name='product[tier_price][{{var1}}][percentage_value]']" parameterized="true"/>--> - <!--<element name="specialPrice" type="input" selector="input[name='product[special_price]']"/>--> - <element name="enableQtyIncrements" type="select" selector="//*[@name='product[stock_data][enable_qty_increments]']"/> <element name="enableQtyIncrementsOptions" type="select" selector="//*[@name='product[stock_data][enable_qty_increments]']//option[contains(@value, '{{var1}}')]" parameterized="true"/> <element name="enableQtyIncrementsUseConfigSettings" type="checkbox" selector="//input[@name='product[stock_data][use_config_enable_qty_inc]']"/> @@ -27,7 +16,6 @@ <element name="qtyUsesDecimalsOptions" type="select" selector="//*[@name='product[stock_data][is_qty_decimal]']//option[contains(@value, '{{var1}}')]" parameterized="true"/> <element name="qtyIncrements" type="input" selector="//input[@name='product[stock_data][qty_increments]']"/> <element name="qtyIncrementsUseConfigSettings" type="checkbox" selector="//input[@name='product[stock_data][use_config_qty_increments]']"/> - <element name="doneButton" type="button" selector="//aside[contains(@class,'product_form_product_form_advanced_inventory_modal')]//button[contains(@data-role,'action')]" timeout="5"/> </section> </sections> diff --git a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml index 6baa3ff54fca0..2b08e9b4b85ec 100644 --- a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml +++ b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml @@ -8,7 +8,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="StorefrontQuickSearchSection">/ + <section name="StorefrontQuickSearchSection"> <element name="searchPhrase" type="input" selector="#search"/> <element name="searchButton" type="button" selector="button.action.search" timeout="30"/> </section> From 3478e785f5a08e6220ff604836cec9199c2f30ba Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Wed, 31 Oct 2018 17:15:41 +0200 Subject: [PATCH 0395/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Fix static tests; --- .../Adminhtml/Edit/Address/CancelButton.php | 1 + .../Adminhtml/Edit/Address/SaveButton.php | 1 + .../Address/AbstractDefaultAddress.php | 4 +- .../Address/DefaultBillingAddress.php | 1 + .../Address/DefaultShippingAddress.php | 1 + .../Controller/Adminhtml/Address/Delete.php | 4 +- .../Adminhtml/Address/MassDelete.php | 10 +- .../Controller/Adminhtml/Address/Save.php | 4 +- .../Controller/Adminhtml/Address/Validate.php | 14 ++- .../Adminhtml/File/Address/Upload.php | 3 +- .../Customer/Model/Address/DataProvider.php | 1 + .../Model/AttributeMetadataResolver.php | 13 +- .../Customer/Model/Customer/DataProvider.php | 14 ++- .../DataProviderWithDefaultAddresses.php | 6 +- .../Model/FileUploaderDataResolver.php | 4 +- .../Model/ResourceModel/Address/Relation.php | 2 - .../Unit/Model/Address/DataProviderTest.php | 62 ++++------ .../ResourceModel/CustomerRepositoryTest.php | 6 - .../Ui/Component/Form/AddressFieldsetTest.php | 2 +- .../Listing/Address/Column/Countries.php | 6 +- .../ui_component/customer_address_form.xml | 2 +- .../web/js/address/default-address.js | 15 ++- app/code/Magento/Ui/Component/Layout/Tabs.php | 115 ++++++++++-------- .../web/css/source/_module.less | 15 +-- 24 files changed, 167 insertions(+), 139 deletions(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php index 6270e8073d0e8..d94b956918370 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php index 0d3a9f57ff5a3..9d403185ca888 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index 75b888bb06675..51e02e9ee096e 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * * Copyright © Magento, Inc. All rights reserved. @@ -7,6 +8,7 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Redirect; use Magento\Framework\Phrase; use Psr\Log\LoggerInterface; @@ -14,7 +16,7 @@ /** * Abstract class for customer default addresses changing */ -abstract class AbstractDefaultAddress extends Action +abstract class AbstractDefaultAddress extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php index bd921a5a6642e..41a0a6390edf7 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * * Copyright © Magento, Inc. All rights reserved. diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php index 7d5bef9ab5be9..057b36be79124 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * * Copyright © Magento, Inc. All rights reserved. diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 1620f343700ed..7630dba780357 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * * Copyright © Magento, Inc. All rights reserved. @@ -7,13 +8,14 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Redirect; use Magento\Customer\Api\AddressRepositoryInterface; /** * Button for deletion of customer address in admin * */ -class Delete extends Action +class Delete extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index 2ea4b79f78028..b8df3fdf81599 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -1,20 +1,24 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Controller\Adminhtml\Address; +use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Backend\Model\View\Result\Redirect; /** * Class to delete selected customer addresses through massaction */ -class MassDelete extends \Magento\Backend\App\Action +class MassDelete extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session @@ -59,10 +63,10 @@ public function __construct( /** * Delete specified customer addresses using grid massaction * - * @return \Magento\Backend\Model\View\Result\Redirect + * @return Redirect * @throws \Magento\Framework\Exception\LocalizedException|\Exception */ - public function execute() + public function execute(): Redirect { /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ $collection = $this->filter->getCollection($this->collectionFactory->create()); diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 9113640112e3b..8b70263d3f95b 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. @@ -6,13 +7,14 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Redirect; use Psr\Log\LoggerInterface; /** * Class for saving of customer address */ -class Save extends Action +class Save extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php index e4583230d5294..16a40fd9016f8 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -1,19 +1,21 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\DataObject; /** * Class for validation of customer address form on admin. */ -class Validate extends \Magento\Backend\App\Action implements HttpPostActionInterface, HttpGetActionInterface +class Validate extends Action implements HttpPostActionInterface, HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -50,9 +52,9 @@ public function __construct( /** * AJAX customer address validation action * - * @return \Magento\Framework\Controller\Result\Json + * @return Json */ - public function execute() + public function execute(): Json { /** @var \Magento\Framework\DataObject $response */ $response = new \Magento\Framework\DataObject(); @@ -74,10 +76,10 @@ public function execute() /** * Customer address validation. * - * @param \Magento\Framework\DataObject $response + * @param DataObject $response * @return \Magento\Framework\DataObject */ - private function validateCustomerAddress(\Magento\Framework\DataObject $response) + private function validateCustomerAddress(DataObject $response): DataObject { $addressForm = $this->formFactory->create('customer_address', 'adminhtml_customer_address'); $formData = $addressForm->extractData($this->getRequest()); diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php index be1b1aec7b3a3..afa62d2148eb4 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php @@ -10,6 +10,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Model\FileUploader; use Magento\Customer\Model\FileUploaderFactory; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; @@ -17,7 +18,7 @@ /** * Uploads files for customer address */ -class Upload extends Action +class Upload extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 5fd7c884cf6b5..1b4bcf94fec15 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -85,6 +85,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param array $data * @param bool $allowToShowHiddenAttributes * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( $name, diff --git a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php index 36ffcb2f5495b..6b006d7f44e7e 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php @@ -19,6 +19,7 @@ /** * Class to build meta data of the customer or customer address attribute + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class AttributeMetadataResolver { @@ -188,8 +189,16 @@ private function canShowAttributeInForm(AbstractAttribute $customerAttribute, st if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { return \is_array($customerAttribute->getUsedInForms()) && ( - (\in_array('customer_account_create', $customerAttribute->getUsedInForms(), true) && $isRegistration) || - (\in_array('customer_account_edit', $customerAttribute->getUsedInForms(), true) && !$isRegistration) + (\in_array( + 'customer_account_create', + $customerAttribute->getUsedInForms(), + true + ) && $isRegistration) || + (\in_array( + 'customer_account_edit', + $customerAttribute->getUsedInForms(), + true + ) && !$isRegistration) ); } return \is_array($customerAttribute->getUsedInForms()) && diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index c834dd26824cd..7b770d20263dc 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -29,6 +29,8 @@ use Magento\Ui\DataProvider\EavValidationRules; /** + * Data provider for customer and customer address data and meta data + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * * @deprecated \Magento\Customer\Model\Address\DataProvider is used instead @@ -148,18 +150,20 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider private $allowToShowHiddenAttributes; /** - * @param string $name - * @param string $primaryFieldName - * @param string $requestFieldName + * DataProvider constructor. + * @param $name + * @param $primaryFieldName + * @param $requestFieldName * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig * @param FilterPool $filterPool - * @param FileProcessorFactory $fileProcessorFactory - * @param ContextInterface $context + * @param FileProcessorFactory|null $fileProcessorFactory * @param array $meta * @param array $data + * @param ContextInterface|null $context * @param bool $allowToShowHiddenAttributes + * @throws \Magento\Framework\Exception\LocalizedException * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 9131fb2ccdce2..eafa5907efac9 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -42,11 +42,6 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract 'confirmation', ]; - /* - * @var ContextInterface - */ - private $context; - /** * Allow to manage attributes, even they are hidden on storefront * @@ -83,6 +78,7 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract * @param array $meta * @param array $data * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( string $name, diff --git a/app/code/Magento/Customer/Model/FileUploaderDataResolver.php b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php index a132507deaa2f..9dd5084739c74 100644 --- a/app/code/Magento/Customer/Model/FileUploaderDataResolver.php +++ b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php @@ -39,7 +39,9 @@ class FileUploaderDataResolver /** * @param FileProcessorFactory $fileProcessorFactory */ - public function __construct(FileProcessorFactory $fileProcessorFactory) { + public function __construct( + FileProcessorFactory $fileProcessorFactory + ) { $this->fileProcessorFactory = $fileProcessorFactory; } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index cbfebe87812bc..37a633d47f512 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -46,7 +46,6 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) $changedAddresses['default_billing'] = $object->getId(); } elseif ($customer->getDefaultBillingAddress() && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() - && !$object->getIsDefaultBilling() ) { $changedAddresses['default_billing'] = null; } @@ -55,7 +54,6 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) $changedAddresses['default_shipping'] = $object->getId(); } elseif ($customer->getDefaultShippingAddress() && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() - && !$object->getIsDefaultShipping() ) { $changedAddresses['default_shipping'] = null; } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php index 815a47288e370..81266a8934c87 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -7,16 +7,15 @@ namespace Magento\Customer\Test\Unit\Model\Address; use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\AttributeMetadataResolver; +use Magento\Customer\Model\FileUploaderDataResolver; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; use Magento\Customer\Model\ResourceModel\Address\Collection as AddressCollection; use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Type; -use Magento\Ui\DataProvider\EavValidationRules; -use Magento\Customer\Model\Attribute as AttributeModel; use Magento\Customer\Api\Data\CustomerInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Customer\Model\Address as AddressModel; -use Magento\Customer\Model\FileProcessorFactory; class DataProviderTest extends \PHPUnit\Framework\TestCase { @@ -45,26 +44,11 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase */ private $eavConfig; - /** - * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject - */ - private $eavValidationRules; - /* * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject */ private $context; - /** - * @var \Magento\Customer\Model\Config\Share|\PHPUnit_Framework_MockObject_MockObject - */ - private $shareConfig; - - /** - * @var FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $fileProcessorFactory; - /** * @var Type|\PHPUnit_Framework_MockObject_MockObject */ @@ -76,9 +60,14 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase private $address; /** - * @var AttributeModel|\PHPUnit_Framework_MockObject_MockObject + * @var FileUploaderDataResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileUploaderDataResolver; + + /** + * @var AttributeMetadataResolver|\PHPUnit_Framework_MockObject_MockObject */ - private $attribute; + private $attributeMetadataResolver; /** * @var \Magento\Customer\Model\Address\DataProvider @@ -88,6 +77,12 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase protected function setUp() { $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->fileUploaderDataResolver = $this->getMockBuilder(FileUploaderDataResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->attributeMetadataResolver = $this->getMockBuilder(AttributeMetadataResolver::class) + ->disableOriginalConstructor() + ->getMock(); $this->addressCollectionFactory = $this->getMockBuilder(CollectionFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) @@ -96,13 +91,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); $this->customerRepository = $this->getMockForAbstractClass(CustomerRepositoryInterface::class); - $this->eavValidationRules = $this->createMock(EavValidationRules::class); $this->context = $this->getMockForAbstractClass(ContextInterface::class); - $this->fileProcessorFactory = $this->getMockBuilder(FileProcessorFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->shareConfig = $this->createMock(\Magento\Customer\Model\Config\Share::class); $this->addressCollectionFactory->expects($this->once()) ->method('create') ->willReturn($this->collection); @@ -122,9 +111,6 @@ protected function setUp() $this->address = $this->getMockBuilder(AddressModel::class) ->disableOriginalConstructor() ->getMock(); - $this->attribute = $this->getMockBuilder(AttributeModel::class) - ->disableOriginalConstructor() - ->getMock(); $this->model = $objectManagerHelper->getObject( \Magento\Customer\Model\Address\DataProvider::class, @@ -135,10 +121,9 @@ protected function setUp() 'addressCollectionFactory' => $this->addressCollectionFactory, 'customerRepository' => $this->customerRepository, 'eavConfig' => $this->eavConfig, - 'eavValidationRules' => $this->eavValidationRules, 'context' => $this->context, - 'fileProcessorFactory' => $this->fileProcessorFactory, - 'shareConfig' => $this->shareConfig, + 'fileUploaderDataResolver' => $this->fileUploaderDataResolver, + 'attributeMetadataResolver' => $this->attributeMetadataResolver, [], [], true @@ -146,7 +131,7 @@ protected function setUp() ); } - public function testGetDefaultData() + public function testGetDefaultData(): void { $expectedData = [ '' => [ @@ -176,7 +161,7 @@ public function testGetDefaultData() $this->assertEquals($expectedData, $this->model->getData()); } - public function testGetData() + public function testGetData(): void { $expectedData = [ '3' => [ @@ -221,12 +206,9 @@ public function testGetData() 'lastname' => 'Doe', 'street' => "42000 Ave W 55 Cedar City\nApt. 33" ]); - $this->address->expects($this->once()) - ->method('getAttributes') - ->willReturn([$this->attribute]); - $this->attribute->expects($this->once()) - ->method('getFrontendInput') - ->willReturn(null); + $this->fileUploaderDataResolver->expects($this->once()) + ->method('overrideFileUploaderData') + ->willReturnSelf(); $this->assertEquals($expectedData, $this->model->getData()); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index 1d262e7549873..034832ce72bfb 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -377,12 +377,6 @@ public function testSaveWithPasswordHash() 'getFirstFailure', 'getLockExpires', ]); - $region = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\RegionInterface::class, - [], - '', - false - ); $origCustomer = $this->customer; $customerModel = $this->createPartialMock(\Magento\Customer\Model\Customer::class, [ diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php index 82ce4249bcd85..31a8a1bfacc64 100644 --- a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Ui\Test\Unit\Component\Form; +namespace Magento\Customer\Test\Unit\Ui\Component\Form; use Magento\Customer\Ui\Component\Form\AddressFieldset; use Magento\Framework\View\Element\UiComponent\ContextInterface; diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php index 438a16ec3ba55..d05d5d1c592a7 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php @@ -1,5 +1,9 @@ <?php - +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ namespace Magento\Customer\Ui\Component\Listing\Address\Column; use Magento\Framework\Data\OptionSourceInterface; diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 1c30d08879eed..a2258d7380e24 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -60,7 +60,7 @@ <dataType>text</dataType> </settings> </field> - <field name="default_billing" sortOrder="10" formElement="checkbox"> + <field name="default_billing" sortOrder="6" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index 3a1500e5dc99e..b4ec734cb4033 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -9,16 +9,23 @@ define([ 'use strict'; return Button.extend({ + defaults: { + entity_id: null, + parent_id: null + }, + + /** + * Initializes component. + * + * @returns {Button} + */ initialize: function () { this._super(); if (!this.parent_id) { this.visible(this.entity_id); } - }, - defaults: { - entity_id: null, - parent_id: null + return this; }, /** diff --git a/app/code/Magento/Ui/Component/Layout/Tabs.php b/app/code/Magento/Ui/Component/Layout/Tabs.php index 02e8979f525ef..f5a9c86977c3c 100644 --- a/app/code/Magento/Ui/Component/Layout/Tabs.php +++ b/app/code/Magento/Ui/Component/Layout/Tabs.php @@ -5,10 +5,8 @@ */ namespace Magento\Ui\Component\Layout; -use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\UiComponent\BlockWrapperInterface; use Magento\Framework\View\Element\UiComponent\DataSourceInterface; -use Magento\Framework\View\Element\UiComponent\LayoutInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; use Magento\Ui\Component\Form\Fieldset; @@ -17,7 +15,7 @@ /** * Class Tabs */ -class Tabs extends \Magento\Framework\View\Layout\Generic implements LayoutInterface +class Tabs extends \Magento\Framework\View\Layout\Generic { /** * @var string @@ -97,54 +95,8 @@ protected function addChildren(array &$topNode, UiComponentInterface $component, $name = $childComponent->getName(); $config = $childComponent->getData('config'); $collectedComponents[$name] = true; - if (isset($config['is_collection']) && $config['is_collection'] === true) { - $label = $childComponent->getData('config/label'); - $this->component->getContext()->addComponentDefinition( - 'collection', - [ - 'component' => 'Magento_Ui/js/form/components/collection', - 'extends' => $this->namespace - ] - ); - - /** - * @var UiComponentInterface $childComponent - * @var array $structure - */ - list($childComponent, $structure) = $this->prepareChildComponents($childComponent, $name); - - $childrenStructure = $structure[$name]['children']; - - $structure[$name]['children'] = [ - $name . '_collection' => [ - 'type' => 'collection', - 'config' => [ - 'active' => 1, - 'removeLabel' => __('Remove %1', $label), - 'addLabel' => __('Add New %1', $label), - 'removeMessage' => $childComponent->getData('config/removeMessage'), - 'itemTemplate' => 'item_template', - ], - 'children' => [ - 'item_template' => ['type' => $this->namespace, - 'isTemplate' => true, - 'component' => 'Magento_Ui/js/form/components/collection/item', - 'childType' => 'group', - 'config' => [ - 'label' => __('New %1', $label), - ], - 'children' => $childrenStructure - ] - ] - ] - ]; - } else { - /** - * @var UiComponentInterface $childComponent - * @var array $structure - */ - list($childComponent, $structure) = $this->prepareChildComponents($childComponent, $name); - } + + [$childComponent, $structure] = $this->buildChildComponentStructure($config, $childComponent); $tabComponent = $this->createTabComponent($childComponent, $name); @@ -172,6 +124,67 @@ protected function addChildren(array &$topNode, UiComponentInterface $component, $topNode = $this->structure; } + /** + * Build child components structure of the tab + * + * @param array $config + * @param UiComponentInterface $childComponent + * @return array + */ + private function buildChildComponentStructure(array $config, $childComponent): array + { + $name = $childComponent->getName(); + if (isset($config['is_collection']) && $config['is_collection'] === true) { + $label = $childComponent->getData('config/label'); + $this->component->getContext()->addComponentDefinition( + 'collection', + [ + 'component' => 'Magento_Ui/js/form/components/collection', + 'extends' => $this->namespace + ] + ); + /** + * @var UiComponentInterface $childComponent + * @var array $structure + */ + [$childComponent, $structure] = $this->prepareChildComponents($childComponent, $name); + + $childrenStructure = $structure[$name]['children']; + + $structure[$name]['children'] = [ + $name . '_collection' => [ + 'type' => 'collection', + 'config' => [ + 'active' => 1, + 'removeLabel' => __('Remove %1', $label), + 'addLabel' => __('Add New %1', $label), + 'removeMessage' => $childComponent->getData('config/removeMessage'), + 'itemTemplate' => 'item_template', + ], + 'children' => [ + 'item_template' => ['type' => $this->namespace, + 'isTemplate' => true, + 'component' => 'Magento_Ui/js/form/components/collection/item', + 'childType' => 'group', + 'config' => [ + 'label' => __('New %1', $label), + ], + 'children' => $childrenStructure + ] + ] + ] + ]; + } else { + /** + * @var UiComponentInterface $childComponent + * @var array $structure + */ + [$childComponent, $structure] = $this->prepareChildComponents($childComponent, $name); + } + + return [$childComponent, $structure]; + } + /** * Add wrapped layout block * diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index 8a5fe698eb196..876859ff38d1a 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -3,7 +3,7 @@ // * See COPYING.txt for license details. // */ -.customer_form_areas_address_address_customer_address_update_modal_update_customer_address_form_loader { +.customer_form_areas_address_address_customer_address_update_modal_update_customer_address_form_loader { .admin__field { .admin__field { .admin__field-label { @@ -15,10 +15,12 @@ .customer-address-form { - *, *:before, *:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; + *, + *:before, + *:after { box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } address { @@ -26,8 +28,7 @@ } .customer-default-billing-address-content, - .customer-default-shipping-address-content - { + .customer-default-shipping-address-content { float: left; width: 550px; } @@ -52,10 +53,10 @@ } .add-new-address-button { - position: relative; clear: both; float: right; margin-bottom: 30px; + position: relative; } .address-information { From 47251f6b9802a579fadd55146c649c1a2bf04140 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 31 Oct 2018 10:24:09 -0500 Subject: [PATCH 0396/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Added the out of stock filter to the grouped product model to replicate frontend behavior --- .../Model/Product/Type/Grouped.php | 14 +++- .../Api/CartItemRepositoryTest.php | 68 +++++++++++++++++ ...oduct_grouped_with_simple_out_of_stock.php | 75 +++++++++++++++++++ ...uped_with_simple_out_of_stock_rollback.php | 34 +++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php create mode 100644 dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 80824d45cb6e5..8844aedcb3d99 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -8,6 +8,8 @@ namespace Magento\GroupedProduct\Model\Product\Type; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\App\ObjectManager; +use Magento\CatalogInventory\Helper\Stock as StockHelper; /** * Grouped product type model @@ -86,6 +88,11 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ protected $msrpData; + /** + * @var \Magento\CatalogInventory\Helper\Stock|null + */ + private $stockHelper; + /** * @param \Magento\Catalog\Model\Product\Option $catalogProductOption * @param \Magento\Eav\Model\Config $eavConfig @@ -102,6 +109,7 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType * @param \Magento\Framework\App\State $appState * @param \Magento\Msrp\Helper\Data $msrpData * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer + * @param \Magento\CatalogInventory\Helper\Stock|null $stockHelper * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -119,13 +127,15 @@ public function __construct( \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus, \Magento\Framework\App\State $appState, \Magento\Msrp\Helper\Data $msrpData, - \Magento\Framework\Serialize\Serializer\Json $serializer = null + \Magento\Framework\Serialize\Serializer\Json $serializer = null, + StockHelper $stockHelper = null ) { $this->productLinks = $catalogProductLink; $this->_storeManager = $storeManager; $this->_catalogProductStatus = $catalogProductStatus; $this->_appState = $appState; $this->msrpData = $msrpData; + $this->stockHelper = $stockHelper ?: ObjectManager::getInstance()->get(StockHelper::class); parent::__construct( $catalogProductOption, $eavConfig, @@ -218,6 +228,8 @@ public function getAssociatedProducts($product) ['in' => $this->getStatusFilters($product)] ); + $this->stockHelper->addIsInStockFilterToCollection($collection); + foreach ($collection as $item) { $associatedProducts[] = $item; } diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php new file mode 100644 index 0000000000000..61f07ac3aa043 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php @@ -0,0 +1,68 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\GroupedProduce\Api; + +use Magento\Catalog\Model\CustomOptions\CustomOptionProcessor; +use Magento\Framework\Webapi\Rest\Request; +use Magento\Quote\Model\Quote; +use Magento\TestFramework\TestCase\WebapiAbstract; + +class CartItemRepositoryTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'quoteCartItemRepositoryV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php + */ + public function testAddGroupedProductToCartThatHasAnOutOfStockItemInTheGroup() + { + $this->_markTestAsRestOnly(); + + /** @var \Magento\Catalog\Model\Product $product */ + $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class)->load('100000003'); + $productSku = $product->getSku(); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items', + 'httpMethod' => Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData = [ + 'cartItem' => [ + 'sku' => $productSku, + 'qty' => 1, + 'quote_id' => $cartId, + ], + ]; + $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($quote->hasProductId('100000001')); + $this->assertFalse($quote->hasProductId('100000002')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php new file mode 100644 index 0000000000000..6ef9b5cd5b0a8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\GroupedProduct\Model\Product\Type\Grouped; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = Bootstrap::getObjectManager() + ->get(ProductRepositoryInterface::class); + +$productLinkFactory = Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory::class); +$productConfigs = [ + [ + 'id' => '100000001', + 'stock_config' => ['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1] + ], + [ + 'id' => '100000002', + 'stock_config' => ['use_config_manage_stock' => 1, 'qty' => 0, 'is_qty_decimal' => 0, 'is_in_stock' => 0] + ] +]; + +foreach ($productConfigs as $productConfig) { + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId($productConfig['id']) + ->setWebsiteIds([1]) + ->setAttributeSetId(4) + ->setName('Simple ' . $productConfig['id']) + ->setSku('simple_' . $productConfig['id']) + ->setPrice(100) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData($productConfig['stock_config']); + + $linkedProducts[] = $productRepository->save($product); +} + +/** @var $product Product */ +$product = Bootstrap::getObjectManager()->create(Product::class); + +$product->setTypeId(Grouped::TYPE_CODE) + ->setId('100000003') + ->setWebsiteIds([1]) + ->setAttributeSetId(4) + ->setName('Grouped Product') + ->setSku('grouped') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); + +foreach ($linkedProducts as $linkedProduct) { + /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */ + $productLink = $productLinkFactory->create(); + $productLink->setSku($product->getSku()) + ->setLinkType('associated') + ->setLinkedProductSku($linkedProduct->getSku()) + ->setLinkedProductType($linkedProduct->getTypeId()) + ->getExtensionAttributes() + ->setQty(1); + $newLinks[] = $productLink; +} + +$product->setProductLinks($newLinks); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php new file mode 100644 index 0000000000000..b81c008cf1ab6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$skuList = ['simple_100000001', 'simple_100000002', 'grouped']; +foreach ($skuList as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + + $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class); + $stockStatus->load($product->getData('entity_id'), 'product_id'); + $stockStatus->delete(); + + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From d70ff4be68f9e084cc4e11de4092a6775e452b92 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Wed, 31 Oct 2018 10:38:14 -0500 Subject: [PATCH 0397/1158] MAGETWO-95773: Credit memo is created instead of returning error via invoice refund API for Bundle product - fix unit and static tests --- .../Validation/CreationQuantityValidator.php | 5 +++++ .../Sales/Model/Order/ItemRepository.php | 4 ++-- .../Unit/Model/Order/ItemRepositoryTest.php | 22 +++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php index fdc5e2658b9ed..93a4e701e0322 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php @@ -30,6 +30,7 @@ class CreationQuantityValidator implements ValidatorInterface /** * ItemCreationQuantityValidator constructor. + * * @param OrderItemRepositoryInterface $orderItemRepository * @param mixed $context */ @@ -65,6 +66,8 @@ public function validate($entity) } /** + * Check the quantity to refund is greater than the unrefunded quantity + * * @param Item $orderItem * @param int $qty * @return bool @@ -75,6 +78,8 @@ private function isQtyAvailable(Item $orderItem, $qty) } /** + * Check to see if Item is part of the order + * * @param OrderItemInterface $orderItem * @return bool */ diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index 2ea9831336cc2..b1ff747d4f487 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -95,7 +95,7 @@ public function __construct( } /** - * load entity + * Load entity * * @param int $id * @return OrderItemInterface @@ -230,7 +230,7 @@ private function addParentItem(OrderItemInterface $orderItem) $orderItem->setParentItem($this->get($parentId)); } else { foreach ($orderItem->getOrder()->getAllItems() as $item) { - if($item->getParentItemId() === $orderItem->getItemId()) { + if ($item->getParentItemId() === $orderItem->getItemId()) { $item->setParentItem($orderItem); } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php index 8be2c3c8612d7..c19b4cbc3cb50 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php @@ -156,18 +156,27 @@ public function testGet() $productOption = $this->getProductOptionMock(); $orderItemMock = $this->getOrderMock($productType, $productOption); + $orderMock = $this->createMock(\Magento\Sales\Model\Order::class); + $orderMock->expects($this->once()) + ->method('getAllItems') + ->willReturn([$orderItemMock]); + $orderItemMock->expects($this->once()) ->method('load') ->with($orderItemId) ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) + $orderItemMock->expects($this->exactly(2)) ->method('getItemId') ->willReturn($orderItemId); + $orderItemMock->expects($this->once()) + ->method('getOrder') + ->willReturn($orderMock); $this->metadata->expects($this->once()) ->method('getNewInstance') ->willReturn($orderItemMock); + $model = $this->getModel($orderItemMock, $productType); $this->assertSame($orderItemMock, $model->get($orderItemId)); @@ -213,11 +222,17 @@ public function testDeleteById() $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) ->disableOriginalConstructor() ->getMock(); + + $orderMock = $this->createMock(\Magento\Sales\Model\Order::class); + $orderMock->expects($this->once()) + ->method('getAllItems') + ->willReturn([$orderItemMock]); + $orderItemMock->expects($this->once()) ->method('load') ->with($orderItemId) ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) + $orderItemMock->expects($this->exactly(2)) ->method('getItemId') ->willReturn($orderItemId); $orderItemMock->expects($this->once()) @@ -226,6 +241,9 @@ public function testDeleteById() $orderItemMock->expects($this->once()) ->method('getBuyRequest') ->willReturn($requestMock); + $orderItemMock->expects($this->once()) + ->method('getOrder') + ->willReturn($orderMock); $orderItemResourceMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) ->disableOriginalConstructor() From d9f0d55a0fc1310665eef30ad66405af5cac70d1 Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Wed, 31 Oct 2018 19:42:45 +0400 Subject: [PATCH 0398/1158] MAGETWO-91639: Tax is added despite customer group changes - Updated automated test --- .../Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml index fd5cf8d43d8fb..c44ce895bc825 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -15,7 +15,7 @@ <amOnPage url="{{AdminCustomerGroupPage.url}}" stepKey="navigateToCustomersGroupPage"/> <waitForPageLoad stepKey="waitForPageOpened"/> <click stepKey="clickFiltersBtn" selector="{{AdminCustomerGroupMainSection.filterBtn}}"/> - <fillField selector="{{AdminCustomerGroupMainSection.groupField}}" userInput="{{groupName}}" stepKey="fillFieldGroupName"/> + <fillField selector="{{AdminCustomerGroupMainSection.groupField}}" userInput="{{customerGroupName}}" stepKey="fillFieldGroupName"/> <click stepKey="clickApplyBtn" selector="{{AdminCustomerGroupMainSection.applyFiltersBtn}}"/> <!--Here we need to use Implicit wait.--> <wait stepKey="waitForFilteringFinished" time="2"/> @@ -23,7 +23,7 @@ <wait stepKey="waitForDropDownOpened" time="2"/> <click stepKey="clickDeleteBtn" selector="{{AdminCustomerGroupMainSection.deleteBtn}}"/> <waitForPageLoad stepKey="waitForConfirmationAlert"/> - <click stepKey="accept" selector="{{AdminCustomerGridMainActionsSection.ok}}"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="acceptMessage"/> <see stepKey="seeSuccessMessage" userInput="You deleted the customer group."/> <wait stepKey="waitForClearAllBtnVisible" time="2"/> <click stepKey="clearAllBtn" selector="{{AdminCustomerGroupMainSection.clearAllBtn}}"/> From 413a03686976ccf06c240783ddfdd2632af6d7cc Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Wed, 31 Oct 2018 13:15:39 -0500 Subject: [PATCH 0399/1158] MAGETWO-95773: Credit memo is created instead of returning error via invoice refund API for Bundle product - remove empty line --- .../Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php index c19b4cbc3cb50..5e1b49c0013e3 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php @@ -176,7 +176,6 @@ public function testGet() ->method('getNewInstance') ->willReturn($orderItemMock); - $model = $this->getModel($orderItemMock, $productType); $this->assertSame($orderItemMock, $model->get($orderItemId)); From 5d84640f097dd94a361a6b0b1085e13da472a360 Mon Sep 17 00:00:00 2001 From: Joan He <johe@adobe.com> Date: Wed, 31 Oct 2018 20:17:21 -0500 Subject: [PATCH 0400/1158] MAGETWO-95659: Fix and Unskip MTF OnePageCheckoutOfflinePaymentMethodsTest --- .../OnePageCheckoutOfflinePaymentMethodsTest.xml | 11 ++++------- .../Test/TestStep/SelectCheckoutMethodStep.php | 11 +++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml index 7c12b546d1359..361c5031f3317 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml @@ -22,7 +22,6 @@ <constraint name="Magento\Shipping\Test\Constraint\AssertShipmentSuccessCreateMessage" /> </variation> <variation name="OnePageCheckoutUsingRegisterLink" summary="Customer is redirected to checkout on login if guest is disabled, flow with registration new Customer" ticketId="MAGETWO-49917"> - <data name="issue" xsi:type="string">MAGETWO-59816: Redirect works improperly in a browser incognito mode</data> <data name="tag" xsi:type="string">severity:S1</data> <data name="products/0" xsi:type="string">catalogProductSimple::default</data> <data name="customer/dataset" xsi:type="string">register_customer</data> @@ -57,7 +56,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> </variation> <variation name="OnePageCheckoutTestVariation2" summary="US customer during checkout using coupon for all customer groups"> - <data name="tag" xsi:type="string">stable:no, severity:S0</data> + <data name="tag" xsi:type="string">severity:S0</data> <data name="products/0" xsi:type="string">catalogProductSimple::default</data> <data name="salesRule" xsi:type="string">active_sales_rule_for_all_groups</data> <data name="customer/dataset" xsi:type="string">default</data> @@ -79,7 +78,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> </variation> <variation name="OnePageCheckoutTestVariation3" summary="Checkout as UK guest with simple product" ticketId="MAGETWO-42603, MAGETWO-43282, MAGETWO-43318"> - <data name="tag" xsi:type="string">severity:S1, stable:no</data> + <data name="tag" xsi:type="string">severity:S1</data> <data name="products/0" xsi:type="string">catalogProductSimple::product_with_qty_25</data> <data name="expectedQty/0" xsi:type="string">0</data> <data name="expectedStockStatus/0" xsi:type="string">out of stock</data> @@ -92,7 +91,7 @@ <item name="grandTotal" xsi:type="string">375.00</item> </data> <data name="payment/method" xsi:type="string">banktransfer</data> - <data name="status" xsi:type="string">Precessing</data> + <data name="status" xsi:type="string">Processing</data> <data name="orderButtonsAvailable" xsi:type="string">Back, Send Email, Cancel, Hold, Invoice, Edit</data> <data name="configData" xsi:type="string">banktransfer_specificcountry_gb, can_subtract_and_can_back_in_stock</data> <constraint name="Magento\Shipping\Test\Constraint\AssertShipmentSuccessCreateMessage" /> @@ -102,10 +101,8 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrderStatusIsCorrect" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderButtonsAvailable" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> - <data name="issue" xsi:type="string">MAGETWO-66737: Magento\Checkout\Test\TestCase\OnePageCheckoutTest with OnePageCheckoutTestVariation3 and 4 is not stable</data> </variation> <variation name="OnePageCheckoutTestVariation4" summary="One Page Checkout Products with Special Prices" ticketId="MAGETWO-12429"> - <data name="issue" xsi:type="string">MAGETWO-95659: Fix and Unskip MTF OnePageCheckoutOfflinePaymentMethodsTest</data> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, severity:S0</data> <data name="products/0" xsi:type="string">catalogProductSimple::product_with_special_price</data> <data name="products/1" xsi:type="string">configurableProduct::product_with_special_price</data> @@ -211,7 +208,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> </variation> <variation name="OnePageCheckoutTestVariation9" summary="One Page Checkout Products with different shipping/billing address and Tier Prices" ticketId="MAGETWO-42604"> - <data name="tag" xsi:type="string">stable:no, severity:S1</data> + <data name="tag" xsi:type="string">severity:S1</data> <data name="products/0" xsi:type="string">catalogProductSimple::simple_with_tier_price_and_order_qty_3</data> <data name="customer/dataset" xsi:type="string">default</data> <data name="checkoutMethod" xsi:type="string">login</data> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php index d951d84bab78d..f79cf8d7eb7fa 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php @@ -59,6 +59,13 @@ class SelectCheckoutMethodStep implements TestStepInterface */ private $customerAccountCreatePage; + /** + * Proceed to checkout from minicart step + * + * @var proceedToCheckoutFromMiniShoppingCartStep + */ + private $proceedToCheckoutFromMiniShoppingCartStep; + /** * @constructor * @param CheckoutOnepage $checkoutOnepage @@ -66,6 +73,7 @@ class SelectCheckoutMethodStep implements TestStepInterface * @param Customer $customer * @param LogoutCustomerOnFrontendStep $logoutCustomerOnFrontend * @param ClickProceedToCheckoutStep $clickProceedToCheckoutStep + * @param ProceedToCheckoutFromMiniShoppingCartStep $proceedToCheckoutFromMiniShoppingCartStep * @param string $checkoutMethod */ public function __construct( @@ -74,6 +82,7 @@ public function __construct( Customer $customer, LogoutCustomerOnFrontendStep $logoutCustomerOnFrontend, ClickProceedToCheckoutStep $clickProceedToCheckoutStep, + ProceedToCheckoutFromMiniShoppingCartStep $proceedToCheckoutFromMiniShoppingCartStep, $checkoutMethod ) { $this->checkoutOnepage = $checkoutOnepage; @@ -82,6 +91,7 @@ public function __construct( $this->logoutCustomerOnFrontend = $logoutCustomerOnFrontend; $this->clickProceedToCheckoutStep = $clickProceedToCheckoutStep; $this->checkoutMethod = $checkoutMethod; + $this->proceedToCheckoutFromMiniShoppingCartStep = $proceedToCheckoutFromMiniShoppingCartStep; } /** @@ -129,6 +139,7 @@ private function processRegister() if ($this->checkoutMethod === 'register_before_checkout') { $this->checkoutOnepage->getAuthenticationPopupBlock()->createAccount(); $this->customerAccountCreatePage->getRegisterForm()->registerCustomer($this->customer); + $this->proceedToCheckoutFromMiniShoppingCartStep->run(); } } From a0bb0fcf965d47f617cc801187f6290d8bdf22a6 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Thu, 1 Nov 2018 09:45:21 +0200 Subject: [PATCH 0401/1158] graphQl: updated shipping address coverage content --- .../MultiShipping.php | 69 ++++++++++++++++--- .../MultiShipping/ShippingItemsMapper.php | 43 ++++++++++++ .../SingleShipping.php | 47 +++++++++++-- .../SetShippingAddressesOnCart.php | 32 +++------ .../Magento/QuoteGraphQl/etc/schema.graphqls | 4 ++ 5 files changed, 157 insertions(+), 38 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php index 71560a26c03ee..318fd9361af5a 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php @@ -1,23 +1,76 @@ <?php /** - * @author Atwix Team - * @copyright Copyright (c) 2018 Atwix (https://www.atwix.com/) + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Multishipping\Model\Checkout\Type\Multishipping as MultishippingModel; +use Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\MultiShipping\ShippingItemsMapper; + class MultiShipping { /** + * @var MultishippingModel + */ + private $multishippingModel; + + /** + * @var ShippingItemsMapper + */ + private $shippingItemsInformationMapper; + + /** + * @param MultishippingModel $multishippingModel + * @param ShippingItemsMapper $shippingItemsInformationMapper + */ + public function __construct( + MultishippingModel $multishippingModel, + ShippingItemsMapper $shippingItemsInformationMapper + ) { + $this->multishippingModel = $multishippingModel; + $this->shippingItemsInformationMapper = $shippingItemsInformationMapper; + } + + /** + * @param ContextInterface $context * @param int $cartId - * @param array $cartItems - * @param int|null $customerAddressId - * @param array|null $address - * @return void + * @param array $shippingAddresses */ - public function setAddress(int $cartId, array $cartItems, ?int $customerAddressId, ?array $address): void + public function setAddresses(ContextInterface $context, int $cartId, array $shippingAddresses): void { - //TODO: implement multi shipping + if ((!$context->getUserId()) || $context->getUserType() == UserContextInterface::USER_TYPE_GUEST) { + throw new GraphQlAuthorizationException( + __( + 'Multishipping allowed only for authorized customers' + ) + ); + } + + $shippingItemsInformation = []; + foreach ($shippingAddresses as $shippingAddress) { + $customerAddressId = $shippingAddress['customer_address_id'] ?? null; + $cartItems = $shippingAddress['cart_items'] ?? null; + if (!$customerAddressId) { + throw new GraphQlInputException(__('Parameter "customer_address_id" is required for multishipping')); + } + if (!$cartItems) { + throw new GraphQlInputException(__('Parameter "cart_items" is required for multishipping')); + } + + $shippingItemsInformation = array_merge( + $shippingItemsInformation, + $this->shippingItemsInformationMapper->map($shippingAddress) + ); + } + + //TODO: multishipping model works with session. Do we need to avoid it? + $this->multishippingModel->setShippingItemsInformation($shippingItemsInformation); } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php new file mode 100644 index 0000000000000..c9cefc421a544 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\MultiShipping; + +/** + * Shipping address to shipping items mapper + */ +class ShippingItemsMapper +{ + + /** + * Converts shipping address input array into shipping items information array + * Array structure: + * array( + * $cartItemId => array( + * 'qty' => $qty, + * 'address' => $customerAddressId + * ) + * ) + * + * @param array $shippingAddress + * @return array + */ + public function map(array $shippingAddress): array + { + $shippingItemsInformation = []; + foreach ($shippingAddress['cart_items'] as $cartItem) { + $shippingItemsInformation[] = [ + $cartItem['cart_item_id'] => [ + 'qty' => $cartItem['quantity'], + 'address' => $shippingAddress['customer_address_id'] + ] + ]; + } + + return $shippingItemsInformation; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php index 536a907541b1a..feeb333683f76 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php @@ -1,12 +1,17 @@ <?php /** - * @author Atwix Team - * @copyright Copyright (c) 2018 Atwix (https://www.atwix.com/) + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\ShippingAddressManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; @@ -44,18 +49,46 @@ public function __construct( } /** + * @param ContextInterface $context * @param int $cartId - * @param int|null $customerAddressId - * @param array|null $address + * @param array $shippingAddress * @return void */ - public function setAddress(int $cartId, ?int $customerAddressId, ?array $address): void + public function setAddress(ContextInterface $context, int $cartId, array $shippingAddress): void { - if($customerAddressId) { + $customerAddressId = $shippingAddress['customer_address_id'] ?? null; + $addressInput = $shippingAddress['address'] ?? null; + + if (!$customerAddressId && !$addressInput) { + throw new GraphQlInputException( + __('Shipping address should contain either "customer_address_id" or "address" input.') + ); + } + if ($customerAddressId && $addressInput) { + throw new GraphQlInputException( + __('Shipping address can\'t contain "customer_address_id" and "address" input at the same time.') + ); + } + if ($customerAddressId) { + if ((!$context->getUserId()) || $context->getUserType() == UserContextInterface::USER_TYPE_GUEST) { + throw new GraphQlAuthorizationException( + __( + 'Address management allowed only for authorized customers' + ) + ); + } + /** @var AddressInterface $customerAddress */ $customerAddress = $this->addressRepository->getById($customerAddressId); + if ($context->getUserId() !== (int)$customerAddress->getCustomerId()) { + throw new GraphQlInputException( + __( + 'Address is not applicable for current customer' + ) + ); + } $shippingAddress = $this->addressModel->importCustomerAddressData($customerAddress); } else { - $shippingAddress = $this->addressModel->addData($address); + $shippingAddress = $this->addressModel->addData($addressInput); } $this->shippingAddressManagement->assign($cartId, $shippingAddress); diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php index f3960f66d2792..7ffa6c4950b3d 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php @@ -7,7 +7,6 @@ namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress; -use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; @@ -22,11 +21,6 @@ */ class SetShippingAddressesOnCart implements ResolverInterface { - /** - * @var DataObjectHelper - */ - private $dataObjectHelper; - /** * @var MaskedQuoteIdToQuoteIdInterface */ @@ -48,20 +42,17 @@ class SetShippingAddressesOnCart implements ResolverInterface private $shippingAddressManagement; /** - * @param DataObjectHelper $dataObjectHelper * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param MultiShipping $multiShipping * @param SingleShipping $singleShipping * @param ShippingAddressManagementInterface $shippingAddressManagement */ public function __construct( - DataObjectHelper $dataObjectHelper, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, MultiShipping $multiShipping, SingleShipping $singleShipping, - ShippingAddressManagementInterface $shippingAddressManagement + ShippingAddressManagementInterface $shippingAddressManagement ) { - $this->dataObjectHelper = $dataObjectHelper; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->multiShipping = $multiShipping; $this->singleShipping = $singleShipping; @@ -76,23 +67,18 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value if (!isset($args['input']['cart_id'])) { throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); } + if (!isset($args['input']['shipping_addresses'])) { + throw new GraphQlInputException(__('Required parameter "shipping_addresses" is missing')); + } + + $shippingAddressesInput = $args['input']['shipping_addresses']; $maskedCartId = $args['input']['cart_id']; $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); - $customerAddressId = $args['input']['customer_address_id'] ?? null; - $address = $args['input']['address'] ?? null; - $cartItems = $args['input']['cart_items'] ?? []; - - if (!$customerAddressId && !$address) { - throw new GraphQlInputException(__('Query should contain either address id or address input.')); - } - - //TODO: how to determine whether is multi shipping or not - if (!$cartItems) { - //TODO: assign cart items - $this->singleShipping->setAddress($cartId, $customerAddressId, $address); + if (count($shippingAddressesInput) === 1) { + $this->singleShipping->setAddress($context, $cartId, current($shippingAddressesInput)); } else { - $this->multiShipping->setAddress($cartId, $cartItems, $customerAddressId, $address); + $this->multiShipping->setAddresses($context, $cartId, $shippingAddressesInput); } //TODO: implement Cart object in the separate resolver diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index d13240a23140b..d99182ed10988 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -16,6 +16,10 @@ type Mutation { input SetShippingAddressesOnCartInput { cart_id: String! + shipping_addresses: [ShippingAddressInput!]! +} + +input ShippingAddressInput { customer_address_id: Int # Can be provided in one-page checkout and is required for multi-shipping checkout address: CartAddressInput cart_items: [CartItemQuantityInput!] From 5646ab9d0decf6012ba38dc6d8e974d4d0c51330 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 1 Nov 2018 10:01:32 +0200 Subject: [PATCH 0402/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Fix fail of code compiler; --- app/code/Magento/Customer/Model/Customer/DataProvider.php | 7 +++---- app/code/Magento/Customer/Model/Metadata/Form/File.php | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index 7b770d20263dc..18e78c6bd7baf 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -150,10 +150,9 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider private $allowToShowHiddenAttributes; /** - * DataProvider constructor. - * @param $name - * @param $primaryFieldName - * @param $requestFieldName + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index b9bec01f9ba7c..3959d404d9f55 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -68,7 +68,7 @@ class File extends AbstractData * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param array|string $value + * @param null $value * @param string $entityTypeCode * @param bool $isAjax * @param \Magento\Framework\Url\EncoderInterface $urlEncoder From 24438ed8416bdc370096bae8b8a50425d4f9acd6 Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Thu, 1 Nov 2018 12:33:40 +0400 Subject: [PATCH 0403/1158] MAGETWO-95830: Cannot create credit memo if the used in the order cart rule is deleted - Add automated test --- ...reateCreditMemoWhenCartRuleDeletedTest.xml | 109 ------------------ 1 file changed, 109 deletions(-) delete mode 100644 app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml deleted file mode 100644 index 6ca7c838b7fe7..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWhenCartRuleDeletedTest.xml +++ /dev/null @@ -1,109 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="CreateCreditMemoWhenCartRuleDeletedTest"> - <annotations> - <features value="Sales"/> - <stories value="MAGETWO-95830: Cannot create credit memo if the used in the order cart rule is deleted"/> - <title value="Checking creating of credit memo"/> - <description value="Verify Credit Memo created if the used in the order cart rule is deleted"/> - <severity value="MAJOR"/> - <testCaseId value="MAGETWO-95894"/> - <group value="sales"/> - </annotations> - <before> - <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="_defaultProduct" stepKey="product"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> - </before> - - <!-- Create Cart Price Rule with a specific coupon --> - <actionGroup ref="AdminCreateCartPriceRuleWithCouponCode" stepKey="createCartPriceRule"> - <argument name="ruleName" value="TestSalesRule"/> - <argument name="couponCode" value="_defaultCoupon.code"/> - </actionGroup> - - <!--Go to Storefront. Add product to cart--> - <amOnPage url="/$$product.name$$.html" stepKey="GoToProduct"/> - <actionGroup ref="StorefrontAddToCartCustomOptionsProductPageActionGroup" stepKey="AddProductToCard"> - <argument name="productName" value="$$product.name$$"/> - </actionGroup> - <!--Proceed to checkout--> - <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> - <click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> - <argument name="customerVar" value="CustomerEntityOne" /> - <argument name="customerAddressVar" value="CustomerAddressSimple" /> - </actionGroup> - - <click selector="{{DiscountSection.DiscountTab}}" stepKey="clickToAddDiscount"/> - <fillField selector="{{DiscountSection.DiscountInput}}" userInput="{{_defaultCoupon.code}}" stepKey="TypeDiscountCode"/> - <click selector="{{DiscountSection.ApplyCodeBtn}}" stepKey="clickToApplyDiscount"/> - <waitForPageLoad stepKey="WaitForDiscountToBeAdded"/> - <see userInput="Your coupon was successfully applied." stepKey="verifyText"/> - - <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> - <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> - <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> - - <!--Proceed to Admin panel > SALES > Orders. Created order should be in Processing status--> - <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrdersIndexPage"/> - <waitForPageLoad stepKey="waitForOrderIndexPage"/> - - <!-- Open Order --> - <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> - <argument name="orderId" value="$grabOrderNumber"/> - </actionGroup> - <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> - <waitForPageLoad stepKey="waitForCreatedOrderPageOpened"/> - - <!--Click *Invoice* button--> - <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceButton"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seeNewInvoiceInPageTitle" after="clickInvoiceButton"/> - <waitForPageLoad stepKey="waitForInvoicePageOpened"/> - <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> - <waitForPageLoad stepKey="waitForInvoiceSaved"/> - <see userInput="The invoice has been created." stepKey="seeCorrectMessage"/> - - <!-- Delete the cart price rule --> - <actionGroup ref="DeleteCartPriceRuleByName" stepKey="deleteCartPriceRule"> - <argument name="ruleName" value="{{TestSalesRule.name}}"/> - </actionGroup> - - <!--Proceed to Admin panel > SALES > Orders. Created order should be in Processing status--> - <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrdersIndexPage2"/> - <waitForPageLoad stepKey="waitForOrderIndexPage2"/> - - <!-- Open Order --> - <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById2"> - <argument name="orderId" value="$grabOrderNumber"/> - </actionGroup> - <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow2"/> - <waitForPageLoad stepKey="waitForCreatedOrderPageOpened2"/> - - <!--Admin create credit memo for order--> - <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment"/> - <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreditMemoAction"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> - <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline"/> - - <!--Make sure that Credit memo was created successfully--> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccess"/> - - <after> - <deleteData createDataKey="product" stepKey="deleteProduct"/> - <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <actionGroup ref="logout" stepKey="logOut"/> - </after> - </test> -</tests> From 71983df468f7d5a9ff35e915c59d56c4d33a414b Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Thu, 1 Nov 2018 10:50:59 +0200 Subject: [PATCH 0404/1158] Fix backward incompatibility --- .../Catalog/Model/Product/Gallery/Processor.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index 048ad55985b72..9cd5073f4357c 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -9,7 +9,7 @@ use Magento\Framework\Api\Data\ImageContentInterface; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Filesystem\DriverInterface; +use Magento\Framework\App\ObjectManager; /** * Catalog product Media Gallery attribute processor. @@ -60,7 +60,7 @@ class Processor /** * @var \Magento\Framework\File\Mime */ - protected $mime; + private $mime; /** * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository @@ -68,7 +68,7 @@ class Processor * @param \Magento\Catalog\Model\Product\Media\Config $mediaConfig * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel - * @param \Magento\Framework\File\Mime $mime + * @param \Magento\Framework\File\Mime|null $mime * @throws \Magento\Framework\Exception\FileSystemException */ public function __construct( @@ -77,14 +77,14 @@ public function __construct( \Magento\Catalog\Model\Product\Media\Config $mediaConfig, \Magento\Framework\Filesystem $filesystem, \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel, - \Magento\Framework\File\Mime $mime + \Magento\Framework\File\Mime $mime = null ) { $this->attributeRepository = $attributeRepository; $this->fileStorageDb = $fileStorageDb; $this->mediaConfig = $mediaConfig; $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); $this->resourceModel = $resourceModel; - $this->mime = $mime; + $this->mime = $mime ?: ObjectManager::getInstance()->get(\Magento\Framework\File\Mime::class); } /** From 75e2547a7835330128bdf79e37e314b25f1fc30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20H=C3=BCbner?= <mjh@bergwerk.ag> Date: Mon, 20 Aug 2018 18:37:40 +0300 Subject: [PATCH 0405/1158] Prevent rendering of "Ship here" button to select a shipping item if it is already selected - checks if the item is selected, if it is it does not render the button - removes the css which hides the button currently, because it is not needed anymore --- .../template/shipping-address/address-renderer/default.html | 2 ++ .../web/css/source/module/checkout/_shipping.less | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) 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 2a5dc27328a43..cf64c0140b955 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 @@ -35,7 +35,9 @@ click="editAddress"> <span translate="'Edit'"></span> </button> + <!-- ko if: (!isSelected()) --> <button type="button" click="selectAddress" class="action action-select-shipping-item"> <span translate="'Ship Here'"></span> </button> + <!-- /ko --> </div> diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less index 0a463a95e3182..158cb0ebc0ed1 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less @@ -98,11 +98,6 @@ text-align: center; top: 0; } - - .action-select-shipping-item { - &:extend(.abs-no-display-s all); - visibility: hidden; - } } } From a537b009bbece04073700df55bbd1a0abaf31821 Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Thu, 1 Nov 2018 11:32:05 +0200 Subject: [PATCH 0406/1158] MAGETWO-96026: Create MFTF test for MAGETWO-93973 --- ...gAndQuantityIncrementsWorkWithDecimalinventoryTest.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml index 7a774c585c9cd..e9158e91432fa 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml @@ -1,3 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> <test name="TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest"> From 39dfb2b5e740a315d2274b9ef695716cc94972d2 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Thu, 1 Nov 2018 12:41:22 +0300 Subject: [PATCH 0407/1158] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Converting base order shipping amount for correct calculation; --- app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index 98b854fb07778..e05913bad8735 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -75,10 +75,11 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) } $isPartialShippingRefunded = false; + $baseOrderShippingAmount = (float)$order->getBaseShippingAmount(); if ($invoice = $creditmemo->getInvoice()) { //recalculate tax amounts in case if refund shipping value was changed - if ($order->getBaseShippingAmount() && $creditmemo->getBaseShippingAmount() !== null) { - $taxFactor = $creditmemo->getBaseShippingAmount() / $order->getBaseShippingAmount(); + if ($baseOrderShippingAmount && $creditmemo->getBaseShippingAmount() !== null) { + $taxFactor = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount; $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor; $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor; $totalDiscountTaxCompensation += $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor; @@ -104,7 +105,6 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) } } else { $orderShippingAmount = $order->getShippingAmount(); - $baseOrderShippingAmount = $order->getBaseShippingAmount(); $baseOrderShippingRefundedAmount = $order->getBaseShippingRefunded(); From fe82167bb54618ebc7818d5995533f0a55ffdaaa Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Thu, 1 Nov 2018 11:41:26 +0200 Subject: [PATCH 0408/1158] magento/magento2#17638: [Forwardport]Bundle Special Prices not correctly rounded. --- .../Product/Form/Modifier/Eav.php | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php index d84f496e81915..7379600011bcf 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php @@ -11,6 +11,7 @@ use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\Locator\LocatorInterface; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type as ProductType; use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute; use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory as EavAttributeFactory; use Magento\Catalog\Ui\DataProvider\CatalogEavValidationRules; @@ -419,7 +420,7 @@ public function modifyData(array $data) foreach ($attributes as $attribute) { if (null !== ($attributeValue = $this->setupAttributeData($attribute))) { - if ($attribute->getFrontendInput() === 'price' && is_scalar($attributeValue)) { + if ($this->isPriceAttribute($attribute, $attributeValue)) { $attributeValue = $this->formatPrice($attributeValue); } $data[$productId][self::DATA_SOURCE_DEFAULT][$attribute->getAttributeCode()] = $attributeValue; @@ -430,6 +431,32 @@ public function modifyData(array $data) return $data; } + /** + * Obtain if given attribute is a price + * + * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * @param string|integer $attributeValue + * @return bool + */ + private function isPriceAttribute(ProductAttributeInterface $attribute, $attributeValue) + { + return $attribute->getFrontendInput() === 'price' + && is_scalar($attributeValue) + && !$this->isBundleSpecialPrice($attribute); + } + + /** + * Obtain if current product is bundle and given attribute is special_price + * + * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * @return bool + */ + private function isBundleSpecialPrice(ProductAttributeInterface $attribute) + { + return $this->locator->getProduct()->getTypeId() === ProductType::TYPE_BUNDLE + && $attribute->getAttributeCode() === ProductAttributeInterface::CODE_SPECIAL_PRICE; + } + /** * Resolve data persistence * From daffedf8638585ac230aacd2c1cea18c437a3810 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Thu, 1 Nov 2018 11:45:35 +0200 Subject: [PATCH 0409/1158] MAGETWO-95818: [Magento Cloud] Default value for category URL path does not save - Added reseting category url_path attribute if url_key was set to default value --- .../Model/CategoryUrlPathGenerator.php | 15 +++-- .../CategoryUrlPathAutogeneratorObserver.php | 59 +++++++++++++++---- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php index ee20b0e934b5d..cba9218ce7c72 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php @@ -8,6 +8,9 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Model\Category; +/** + * Class for generation category url_path + */ class CategoryUrlPathGenerator { /** @@ -61,9 +64,11 @@ public function __construct( * Build category URL path * * @param \Magento\Catalog\Api\Data\CategoryInterface|\Magento\Framework\Model\AbstractModel $category + * @param null|\Magento\Catalog\Api\Data\CategoryInterface|\Magento\Framework\Model\AbstractModel $parentCategory * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function getUrlPath($category) + public function getUrlPath($category, $parentCategory = null) { if (in_array($category->getParentId(), [Category::ROOT_CATEGORY_ID, Category::TREE_ROOT_ID])) { return ''; @@ -77,15 +82,17 @@ public function getUrlPath($category) return $category->getUrlPath(); } if ($this->isNeedToGenerateUrlPathForParent($category)) { - $parentPath = $this->getUrlPath( - $this->categoryRepository->get($category->getParentId(), $category->getStoreId()) - ); + $parentCategory = $parentCategory === null ? + $this->categoryRepository->get($category->getParentId(), $category->getStoreId()) : $parentCategory; + $parentPath = $this->getUrlPath($parentCategory); $path = $parentPath === '' ? $path : $parentPath . '/' . $path; } return $path; } /** + * Define whether we should generate URL path for parent + * * @param \Magento\Catalog\Model\Category $category * @return bool */ diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index eb54f0427c11a..b9585fd40ae8b 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -13,6 +13,9 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Store\Model\Store; +/** + * Class observer to initiate generation category url_path + */ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface { /** @@ -46,6 +49,8 @@ public function __construct( } /** + * Generate Category Url Path + * * @param \Magento\Framework\Event\Observer $observer * @return void * @throws \Magento\Framework\Exception\LocalizedException @@ -57,21 +62,40 @@ public function execute(\Magento\Framework\Event\Observer $observer) $useDefaultAttribute = !$category->isObjectNew() && !empty($category->getData('use_default')['url_key']); if ($category->getUrlKey() !== false && !$useDefaultAttribute) { $resultUrlKey = $this->categoryUrlPathGenerator->getUrlKey($category); - if (empty($resultUrlKey)) { - throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key')); - } - $category->setUrlKey($resultUrlKey) - ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); - if (!$category->isObjectNew()) { - $category->getResource()->saveAttribute($category, 'url_path'); - if ($category->dataHasChangedFor('url_path')) { - $this->updateUrlPathForChildren($category); - } + $this->updateUrlKey($category, $resultUrlKey); + } else if ($useDefaultAttribute) { + $resultUrlKey = $category->formatUrlKey($category->getOrigData('name')); + $this->updateUrlKey($category, $resultUrlKey); + $category->setUrlKey(null)->setUrlPath(null); + } + } + + /** + * Update Url Key + * + * @param Category $category + * @param string $urlKey + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + private function updateUrlKey($category, $urlKey) + { + if (empty($urlKey)) { + throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key')); + } + $category->setUrlKey($urlKey) + ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); + if (!$category->isObjectNew()) { + $category->getResource()->saveAttribute($category, 'url_path'); + if ($category->dataHasChangedFor('url_path')) { + $this->updateUrlPathForChildren($category); } } } /** + * Update URL path for children + * * @param Category $category * @return void */ @@ -94,8 +118,13 @@ protected function updateUrlPathForChildren(Category $category) } } else { foreach ($children as $child) { + /** @var Category $child */ $child->setStoreId($category->getStoreId()); - $this->updateUrlPathForCategory($child); + if ($child->getParentId() === $category->getId()) { + $this->updateUrlPathForCategory($child, $category); + } else { + $this->updateUrlPathForCategory($child); + } } } } @@ -112,13 +141,17 @@ protected function isGlobalScope($storeId) } /** + * Update URL path for category + * * @param Category $category + * @param Category|null $parentCategory * @return void + * @throws \Magento\Framework\Exception\NoSuchEntityException */ - protected function updateUrlPathForCategory(Category $category) + protected function updateUrlPathForCategory(Category $category, Category $parentCategory = null) { $category->unsUrlPath(); - $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); + $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category, $parentCategory)); $category->getResource()->saveAttribute($category, 'url_path'); } } From 530d3f5356b09a2c8d0184a2f2da5d29d3224074 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 1 Nov 2018 11:48:04 +0200 Subject: [PATCH 0410/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Static tests fix; --- .../Model/AttributeMetadataResolver.php | 14 ++--- .../Customer/Model/Metadata/Form/File.php | 2 +- .../Model/ResourceModel/Address/Relation.php | 56 +++++++++++++------ .../Unit/Model/Address/DataProviderTest.php | 3 + 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php index 6b006d7f44e7e..c22cc9a4f23f4 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php @@ -189,16 +189,10 @@ private function canShowAttributeInForm(AbstractAttribute $customerAttribute, st if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { return \is_array($customerAttribute->getUsedInForms()) && ( - (\in_array( - 'customer_account_create', - $customerAttribute->getUsedInForms(), - true - ) && $isRegistration) || - (\in_array( - 'customer_account_edit', - $customerAttribute->getUsedInForms(), - true - ) && !$isRegistration) + (\in_array('customer_account_create', $customerAttribute->getUsedInForms(), true) + && $isRegistration) || + (\in_array('customer_account_edit', $customerAttribute->getUsedInForms(), true) + && !$isRegistration) ); } return \is_array($customerAttribute->getUsedInForms()) && diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index 3959d404d9f55..227e85ed98f91 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -68,7 +68,7 @@ class File extends AbstractData * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param null $value + * @param string|array $value * @param string $entityTypeCode * @param bool $isAjax * @param \Magento\Framework\Url\EncoderInterface $urlEncoder diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index 37a633d47f512..a2ba37e7ba1dd 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -7,6 +7,8 @@ */ namespace Magento\Customer\Model\ResourceModel\Address; +use Magento\Customer\Model\Address\AddressModelInterface; +use Magento\Customer\Model\Customer; use Magento\Framework\Model\ResourceModel\Db\VersionControl\RelationInterface; /** @@ -40,23 +42,9 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) */ if (!$object->getIsCustomerSaveTransaction() && $object->getId()) { $customer = $this->customerFactory->create()->load($object->getCustomerId()); - $changedAddresses = []; - if ($object->getIsDefaultBilling()) { - $changedAddresses['default_billing'] = $object->getId(); - } elseif ($customer->getDefaultBillingAddress() - && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() - ) { - $changedAddresses['default_billing'] = null; - } - - if ($object->getIsDefaultShipping()) { - $changedAddresses['default_shipping'] = $object->getId(); - } elseif ($customer->getDefaultShippingAddress() - && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() - ) { - $changedAddresses['default_shipping'] = null; - } + $changedAddresses['default_billing'] = $this->getDefaultBillingChangedAddress($object, $customer); + $changedAddresses['default_shipping'] = $this->getDefaultShippingChangedAddress($object, $customer); if ($changedAddresses) { $customer->getResource()->getConnection()->update( @@ -68,6 +56,42 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) } } + /** + * Get default billing changed address + * + * @param AddressModelInterface $object + * @param Customer $customer + * @return int|null + */ + private function getDefaultBillingChangedAddress(AddressModelInterface $object, Customer $customer): ?int + { + if ($object->getIsDefaultBilling()) { + return $object->getId(); + } elseif ($customer->getDefaultBillingAddress() + && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() + ) { + return null; + } + } + + /** + * Get default shipping changed address + * + * @param AddressModelInterface $object + * @param Customer $customer + * @return int|null + */ + private function getDefaultShippingChangedAddress(AddressModelInterface $object, Customer $customer): ?int + { + if ($object->getIsDefaultShipping()) { + return $object->getId(); + } elseif ($customer->getDefaultShippingAddress() + && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() + ) { + return null; + } + } + /** * Checks if address has chosen as default and has had an id * diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php index 81266a8934c87..92a15ac01fafa 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -17,6 +17,9 @@ use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Customer\Model\Address as AddressModel; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class DataProviderTest extends \PHPUnit\Framework\TestCase { /** From e794db8b1a9fb3b456b1cdaac5303d1888fc9698 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Thu, 1 Nov 2018 12:59:38 +0300 Subject: [PATCH 0411/1158] MAGETWO-91649: Magento ignore store-level url_key of child category in URL rewrite process for global scope - Fixed integration test; --- .../Magento/Catalog/Controller/Adminhtml/CategoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php index a6d03fcc200e2..dad4d21362a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php @@ -403,7 +403,7 @@ public function moveActionDataProvider() { return [ [400, 401, 'first_url_key', 402, 'second_url_key', false], - [400, 401, 'duplicated_url_key', 402, 'duplicated_url_key', true], + [400, 401, 'duplicated_url_key', 402, 'duplicated_url_key', false], [0, 401, 'first_url_key', 402, 'second_url_key', true], [400, 401, 'first_url_key', 0, 'second_url_key', true], ]; From 70f1c939381a9ae123770f80a27b3fcaaf6bfc83 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Thu, 1 Nov 2018 12:02:49 +0200 Subject: [PATCH 0412/1158] MAGETWO-95692: [2.3] Value of Customer Address Attribute is not shown in the Customers grid --- .../Magento/Customer/Model/Indexer/Source.php | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Customer/Model/Indexer/Source.php b/app/code/Magento/Customer/Model/Indexer/Source.php index e4bf03e08a9ad..a8878e2084ea0 100644 --- a/app/code/Magento/Customer/Model/Indexer/Source.php +++ b/app/code/Magento/Customer/Model/Indexer/Source.php @@ -5,6 +5,7 @@ */ namespace Magento\Customer\Model\Indexer; +use Magento\Customer\Model\ResourceModel\Customer\Indexer\CollectionFactory; use Magento\Customer\Model\ResourceModel\Customer\Indexer\Collection; use Magento\Framework\App\ResourceConnection\SourceProviderInterface; use Traversable; @@ -25,11 +26,11 @@ class Source implements \IteratorAggregate, \Countable, SourceProviderInterface private $batchSize; /** - * @param \Magento\Customer\Model\ResourceModel\Customer\Indexer\CollectionFactory $collection + * @param CollectionFactory $collectionFactory * @param int $batchSize */ public function __construct( - \Magento\Customer\Model\ResourceModel\Customer\Indexer\CollectionFactory $collectionFactory, + CollectionFactory $collectionFactory, $batchSize = 10000 ) { $this->customerCollection = $collectionFactory->create(); @@ -37,7 +38,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getMainTable() { @@ -45,7 +46,7 @@ public function getMainTable() } /** - * {@inheritdoc} + * @inheritdoc */ public function getIdFieldName() { @@ -53,7 +54,7 @@ public function getIdFieldName() } /** - * {@inheritdoc} + * @inheritdoc */ public function addFieldToSelect($fieldName, $alias = null) { @@ -62,7 +63,7 @@ public function addFieldToSelect($fieldName, $alias = null) } /** - * {@inheritdoc} + * @inheritdoc */ public function getSelect() { @@ -70,7 +71,7 @@ public function getSelect() } /** - * {@inheritdoc} + * @inheritdoc */ public function addFieldToFilter($attribute, $condition = null) { @@ -79,7 +80,7 @@ public function addFieldToFilter($attribute, $condition = null) } /** - * @return int + * @inheritdoc */ public function count() { @@ -105,4 +106,28 @@ public function getIterator() $pageNumber++; } while ($pageNumber <= $lastPage); } + + /** + * Joins Attribute + * + * @param string $alias alias for the joined attribute + * @param string|\Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute + * @param string $bind attribute of the main entity to link with joined $filter + * @param string|null $filter primary key for the joined entity (entity_id default) + * @param string $joinType inner|left + * @param int|null $storeId + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + * @see Collection::joinAttribute() + */ + public function joinAttribute( + string $alias, + $attribute, + string $bind, + ?string $filter = null, + string $joinType = 'inner', + ?int $storeId = null + ): void { + $this->customerCollection->joinAttribute($alias, $attribute, $bind, $filter, $joinType, $storeId); + } } From 89e371f3638d26d22df0b44af4a16a8adb0abdef Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 1 Nov 2018 12:12:18 +0200 Subject: [PATCH 0413/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Static tests fix; --- .../Customer/Model/ResourceModel/Address/Grid/Collection.php | 1 + .../Customer/Test/Unit/Model/Address/DataProviderTest.php | 1 + .../Model/Customer/DataProviderWithDefaultAddressesTest.php | 1 + .../Test/Unit/Ui/Component/Form/AddressFieldsetTest.php | 2 +- app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php | 2 +- .../Magento/Customer/Controller/Adminhtml/Address/SaveTest.php | 1 + 6 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php index 8026349563867..09aef78b6cebc 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php index 92a15ac01fafa..b1ac27802ff6d 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php index eb1241de3e32c..add6f3525b95e 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php index 31a8a1bfacc64..ba99203c5c6a4 100644 --- a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php @@ -1,9 +1,9 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Customer\Test\Unit\Ui\Component\Form; use Magento\Customer\Ui\Component\Form\AddressFieldset; diff --git a/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php index 9a8cf28ae0719..4ad0b900762db 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php @@ -1,9 +1,9 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Ui\Test\Unit\Component\Form; use Magento\Ui\Component\Form\Fieldset; diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php index 6a41dd70e89e2..c6741f76e0538 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. From 7f1f133d8e1db7d15b9f12d76085f68cdfe94833 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Thu, 1 Nov 2018 14:24:34 +0200 Subject: [PATCH 0414/1158] ENGCOM-1928: Fix file name. --- .../Store/ViewModel/{Switcher.php => SwitcherUrlProvider.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/code/Magento/Store/ViewModel/{Switcher.php => SwitcherUrlProvider.php} (100%) diff --git a/app/code/Magento/Store/ViewModel/Switcher.php b/app/code/Magento/Store/ViewModel/SwitcherUrlProvider.php similarity index 100% rename from app/code/Magento/Store/ViewModel/Switcher.php rename to app/code/Magento/Store/ViewModel/SwitcherUrlProvider.php From 58514a0f25c7596d98b8b135eefa1564f9ed7935 Mon Sep 17 00:00:00 2001 From: shikhamis11 <shikhamishra@cedcoss.com> Date: Thu, 1 Nov 2018 17:59:28 +0530 Subject: [PATCH 0415/1158] fixed store wise product filter issue Fixed issue - #18374 Unable to get product attribute value for store-view scope type in product collection loaded for a specific store. --- .../Magento/Eav/Model/Entity/Collection/AbstractCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php index 0eb87374f3ba3..eba9976260bed 100644 --- a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php +++ b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php @@ -399,7 +399,7 @@ public function addAttributeToFilter($attribute, $condition = null, $joinType = */ public function addFieldToFilter($attribute, $condition = null) { - return $this->addAttributeToFilter($attribute, $condition); + return $this->addAttributeToFilter($attribute, $condition,'left'); } /** From 24b7d98215333a1fa391073420391fdd079034b5 Mon Sep 17 00:00:00 2001 From: Nikita Shcherbatykh <nikita.shcherbatykh@transoftgroup.com> Date: Thu, 1 Nov 2018 15:41:58 +0200 Subject: [PATCH 0416/1158] MAGETWO-95753: [2.3] Cannot save product with Tier Prices --- app/code/Magento/Catalog/Helper/Data.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Helper/Data.php b/app/code/Magento/Catalog/Helper/Data.php index c83eb70486c43..3e96763632830 100644 --- a/app/code/Magento/Catalog/Helper/Data.php +++ b/app/code/Magento/Catalog/Helper/Data.php @@ -413,7 +413,7 @@ public function getAttributeHiddenFields() /** * Retrieve Catalog Price Scope * - * @return int/null + * @return int|null */ public function getPriceScope(): ?int { From d353304c65bd9e8c9eff7841f3a6e4deec403e65 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 1 Nov 2018 15:50:10 +0200 Subject: [PATCH 0417/1158] MAGETWO-95798: All country state's are shown for USA when shipping form has custom address attributes. --- .../Checkout/Test/Mftf/Section/CheckoutShippingSection.xml | 1 + app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml index 494a365ffd507..a8e0c5508ae06 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml @@ -32,5 +32,6 @@ <element name="firstShippingMethod" type="radio" selector="//*[@id='checkout-shipping-method-load']//input[@class='radio']"/> <element name="defaultShipping" type="button" selector=".billing-address-details"/> <element name="stateInput" type="input" selector="input[name=region]"/> + <element name="regionOptions" type="select" selector="select[name=region_id] option"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index d090620145105..2609106b1f19b 100755 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -32,6 +32,7 @@ <data key="vat_id">vatData</data> <data key="default_shipping">true</data> <data key="default_billing">true</data> + <data key="region_qty">66</data> </entity> <entity name="US_Address_TX" type="address"> <data key="firstname">John</data> From 4b399edd7831e8fe2daea25270c910e678e621c2 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Thu, 1 Nov 2018 16:01:43 +0200 Subject: [PATCH 0418/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Fixing static test --- .../Block/Adminhtml/Order/View/Info/PaymentDetails.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php index 40bd0f293a5fd..fb9c74d2f0ab1 100644 --- a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Block\Adminhtml\Order\View\Info; use Magento\Framework\Phrase; From 099465aed038cbdf2884326d5915acd84867d6e0 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Thu, 1 Nov 2018 16:37:19 +0200 Subject: [PATCH 0419/1158] ENGCOM-3201: Updated integration test. --- .../testsuite/Magento/Customer/Controller/Section/LoadTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php index 3e086a89f8140..3563087d3722b 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php @@ -13,7 +13,7 @@ public function testLoadInvalidSection() $expected = [ 'message' => 'The "section<invalid" section source isn't supported.', ]; - $this->dispatch('/customer/section/load/?sections=section<invalid&update_section_id=false&_=147066166394'); + $this->dispatch('/customer/section/load/?sections=section<invalid&force_new_section_timestamp=false&_=147066166394'); self::assertEquals(json_encode($expected), $this->getResponse()->getBody()); } } From 8d9a33db147af98ca918eba5fd00a136f3b7fc04 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Thu, 1 Nov 2018 16:57:13 +0200 Subject: [PATCH 0420/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Fixing static test --- .../Block/Adminhtml/Order/View/Info/PaymentDetails.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php index 40bd0f293a5fd..fb9c74d2f0ab1 100644 --- a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Block\Adminhtml\Order\View\Info; use Magento\Framework\Phrase; From 0ae58d9b877fffedee4ba7eeb40331c63dfcc7a3 Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Thu, 1 Nov 2018 17:10:46 +0200 Subject: [PATCH 0421/1158] MAGETWO-96026: Create MFTF test for MAGETWO-93973 --- .../Catalog/Test/Mftf/Section/AdminProductFormSection.xml | 2 +- ...PricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml index 9ec0dbf9f262c..249610568aec7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml @@ -28,7 +28,7 @@ <element name="advancedPricingLink" type="button" selector="button[data-index='advanced_pricing_button']"/> <element name="categoriesDropdown" type="multiselect" selector="div[data-index='category_ids']"/> <element name="productQuantity" type="input" selector=".admin__field[data-index=qty] input"/> - <element name="advancedInventoryLink" type="input" selector="//button[contains(@data-index, 'advanced_inventory_button')]"/> + <element name="advancedInventoryLink" type="button" selector="//button[contains(@data-index, 'advanced_inventory_button')]"/> <element name="productStockStatus" type="select" selector="select[name='product[quantity_and_stock_status][is_in_stock]']"/> <element name="productWeight" type="input" selector=".admin__field[data-index=weight] input"/> <element name="productWeightSelect" type="select" selector="select[name='product[product_has_weight]']"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml index e9158e91432fa..9dbd2eb0c1fae 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml @@ -45,6 +45,7 @@ <!--Step3. Open *Advanced Pricing* pop-up (Click on *Advanced Pricing* link). Click on *Add* button. Fill *0.5* in *Quantity*--> <scrollTo selector="{{AdminProductFormSection.productName}}" stepKey="scrollToProductName"/> <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingLink1"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForAddButton"/> <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="clickOnCustomerGroupPriceAddButton"/> <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" userInput="0.5" stepKey="fillProductTierPriceQty"/> <!--Step4. Close *Advanced Pricing* (Click on button *Done*). Save *prod1* (Click on button *Save*)--> From 2beca3cec7c782ceff5b10eb9550a41fce4a479d Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Thu, 1 Nov 2018 17:40:35 +0200 Subject: [PATCH 0422/1158] ENGCOM-3063: Update colinmollenhour/cache-backend-redis from version 1.10.5 to 1.10.6 #18294 --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index c6d14eb38bc64..d4ac4fc091bbc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "49fe82043cd4ae944939b6cceade1d1b", + "content-hash": "78153b5c8150c0d145b3372a534a45eb", "packages": [ { "name": "braintree/braintree_php", @@ -88,16 +88,16 @@ }, { "name": "colinmollenhour/cache-backend-redis", - "version": "1.10.5", + "version": "1.10.6", "source": { "type": "git", "url": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis.git", - "reference": "91d949e28d939e607484a4bbf9307cff5afa689b" + "reference": "cc941a5f4cc017e11d3eab9061811ba9583ed6bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/Cm_Cache_Backend_Redis/zipball/91d949e28d939e607484a4bbf9307cff5afa689b", - "reference": "91d949e28d939e607484a4bbf9307cff5afa689b", + "url": "https://api.github.com/repos/colinmollenhour/Cm_Cache_Backend_Redis/zipball/cc941a5f4cc017e11d3eab9061811ba9583ed6bf", + "reference": "cc941a5f4cc017e11d3eab9061811ba9583ed6bf", "shasum": "" }, "require": { @@ -120,7 +120,7 @@ ], "description": "Zend_Cache backend using Redis with full support for tags.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis", - "time": "2018-05-15T16:02:25+00:00" + "time": "2018-09-24T16:02:07+00:00" }, { "name": "colinmollenhour/credis", From 210c4e15364e3a5303515c94906c0eccf9782871 Mon Sep 17 00:00:00 2001 From: Cezary Zeglen <cezary.zeglen@gmail.com> Date: Fri, 24 Aug 2018 17:18:40 +0200 Subject: [PATCH 0423/1158] Fix translations of category design theme not being applied --- app/code/Magento/Catalog/Model/Design.php | 13 ++++++++++++- .../testsuite/Magento/Catalog/Model/DesignTest.php | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Design.php b/app/code/Magento/Catalog/Model/Design.php index bd7cdabb40856..6c0629feaf6fd 100644 --- a/app/code/Magento/Catalog/Model/Design.php +++ b/app/code/Magento/Catalog/Model/Design.php @@ -5,6 +5,8 @@ */ namespace Magento\Catalog\Model; +use \Magento\Framework\TranslateInterface; + /** * Catalog Custom Category design Model * @@ -31,6 +33,11 @@ class Design extends \Magento\Framework\Model\AbstractModel */ protected $_localeDate; + /** + * @var TranslateInterface + */ + private $translator; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -47,10 +54,13 @@ public function __construct( \Magento\Framework\View\DesignInterface $design, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + TranslateInterface $translator = null ) { $this->_localeDate = $localeDate; $this->_design = $design; + $this->translator = $translator ?: + \Magento\Framework\App\ObjectManager::getInstance()->get(TranslateInterface::class); parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -63,6 +73,7 @@ public function __construct( public function applyCustomDesign($design) { $this->_design->setDesignTheme($design); + $this->translator->loadData(null, true); return $this; } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php index 33f26302394f4..38960ab66399a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php @@ -32,8 +32,12 @@ public function testApplyCustomDesign($theme) $design = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Framework\View\DesignInterface::class ); + $translate = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\TranslateInterface::class + ); $this->assertEquals('package', $design->getDesignTheme()->getPackageCode()); $this->assertEquals('theme', $design->getDesignTheme()->getThemeCode()); + $this->assertEquals('themepackage/theme', $translate->getTheme()); } /** From 52381c16a8af9255dc032f13aa80d0dce8d8cd53 Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Thu, 1 Nov 2018 11:21:58 -0500 Subject: [PATCH 0424/1158] MAGETWO-96034: DB compare of upgrade vs fresh install has some inconsistent table schemas --- app/code/Magento/Customer/etc/db_schema.xml | 2 +- app/code/Magento/Integration/etc/db_schema.xml | 2 +- app/code/Magento/Sales/etc/db_schema.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index b3c15799011a2..8178baef71abb 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -506,7 +506,7 @@ <column xsi:type="int" name="customer_id" padding="11" unsigned="false" nullable="true" identity="false" comment="Customer Id"/> <column xsi:type="varchar" name="session_id" nullable="true" length="64" comment="Session ID"/> - <column xsi:type="timestamp" name="last_visit_at" on_update="true" nullable="true" default="CURRENT_TIMESTAMP" + <column xsi:type="timestamp" name="last_visit_at" on_update="true" nullable="false" default="CURRENT_TIMESTAMP" comment="Last Visit Time"/> <constraint xsi:type="primary" referenceId="PRIMARY"> <column name="visitor_id"/> diff --git a/app/code/Magento/Integration/etc/db_schema.xml b/app/code/Magento/Integration/etc/db_schema.xml index c2c2cedc665fb..1f702bfe4bc7a 100644 --- a/app/code/Magento/Integration/etc/db_schema.xml +++ b/app/code/Magento/Integration/etc/db_schema.xml @@ -136,7 +136,7 @@ comment="User type (admin or customer)"/> <column xsi:type="smallint" name="failures_count" padding="5" unsigned="true" nullable="true" identity="false" default="0" comment="Number of failed authentication attempts in a row"/> - <column xsi:type="timestamp" name="lock_expires_at" on_update="true" nullable="true" default="CURRENT_TIMESTAMP" + <column xsi:type="timestamp" name="lock_expires_at" on_update="true" nullable="false" default="CURRENT_TIMESTAMP" comment="Lock expiration time"/> <constraint xsi:type="primary" referenceId="PRIMARY"> <column name="log_id"/> diff --git a/app/code/Magento/Sales/etc/db_schema.xml b/app/code/Magento/Sales/etc/db_schema.xml index 6847b4681de52..ced999bb86019 100644 --- a/app/code/Magento/Sales/etc/db_schema.xml +++ b/app/code/Magento/Sales/etc/db_schema.xml @@ -769,7 +769,7 @@ <column xsi:type="varchar" name="order_increment_id" nullable="false" length="32" comment="Order Increment Id"/> <column xsi:type="int" name="order_id" padding="10" unsigned="true" nullable="false" identity="false" comment="Order Id"/> - <column xsi:type="timestamp" name="order_created_at" on_update="true" nullable="true" + <column xsi:type="timestamp" name="order_created_at" on_update="true" nullable="false" default="CURRENT_TIMESTAMP" comment="Order Increment Id"/> <column xsi:type="varchar" name="customer_name" nullable="false" length="128" comment="Customer Name"/> <column xsi:type="decimal" name="total_qty" scale="4" precision="12" unsigned="false" nullable="true" From a0fddaa2777641013b57a62eac9649efc8d79fe8 Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Thu, 1 Nov 2018 18:45:27 +0200 Subject: [PATCH 0425/1158] MAGETWO-96026: Create MFTF test for MAGETWO-93973 --- ...ingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml index 9dbd2eb0c1fae..6eb78809b187d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml @@ -10,13 +10,13 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> <test name="TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest"> <annotations> - <features value="Tiered pricing and quantity increments work with decimal inventory"/> + <features value="Catalog"/> <stories value="Tiered pricing and quantity increments work with decimal inventory"/> <title value="Tiered pricing and quantity increments work with decimal inventory"/> <description value="Tiered pricing and quantity increments work with decimal inventory"/> <severity value="CRITICAL"/> - <testCaseId value="MAGETWO-91178"/> - <group value="product"/> + <testCaseId value="MAGETWO-93973"/> + <group value="Catalog"/> </annotations> <before> <createData entity="_defaultCategory" stepKey="createPreReqCategory"/> From 547c6fe2f67312c7ba70a8a91adb684766dae98b Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Thu, 1 Nov 2018 11:58:34 -0500 Subject: [PATCH 0426/1158] MAGETWO-95773: Credit memo is created instead of returning error via invoice refund API for Bundle product - use filtered collection for loop --- app/code/Magento/Sales/Model/Order/ItemRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index b1ff747d4f487..cdf5bdf99786e 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -229,7 +229,9 @@ private function addParentItem(OrderItemInterface $orderItem) if ($parentId = $orderItem->getParentItemId()) { $orderItem->setParentItem($this->get($parentId)); } else { - foreach ($orderItem->getOrder()->getAllItems() as $item) { + $orderCollection = $orderItem->getOrder()->getItemsCollection()->filterByParent($orderItem->getItemId()); + + foreach ($orderCollection->getItems() as $item) { if ($item->getParentItemId() === $orderItem->getItemId()) { $item->setParentItem($orderItem); } From 83c4dadf8fc825fbddad9e1361930f38fb37d453 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 1 Nov 2018 19:05:12 +0200 Subject: [PATCH 0427/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Fix address relation model; - Unit tests updated; --- .../Adminhtml/File/Address/Upload.php | 3 +- .../Model/ResourceModel/Address/Relation.php | 45 ++++++++++++------- .../Adminhtml/File/Address/UploadTest.php | 40 +++++++++-------- .../ResourceModel/Address/RelationTest.php | 16 ++++++- 4 files changed, 66 insertions(+), 38 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php index afa62d2148eb4..e9034c8050383 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php @@ -11,6 +11,7 @@ use Magento\Customer\Model\FileUploader; use Magento\Customer\Model\FileUploaderFactory; use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; @@ -18,7 +19,7 @@ /** * Uploads files for customer address */ -class Upload extends Action implements HttpGetActionInterface +class Upload extends Action implements HttpGetActionInterface, HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index a2ba37e7ba1dd..a82a814d40772 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -7,7 +7,7 @@ */ namespace Magento\Customer\Model\ResourceModel\Address; -use Magento\Customer\Model\Address\AddressModelInterface; +use Magento\Customer\Model\Address; use Magento\Customer\Model\Customer; use Magento\Framework\Model\ResourceModel\Db\VersionControl\RelationInterface; @@ -38,13 +38,14 @@ public function __construct(\Magento\Customer\Model\CustomerFactory $customerFac public function processRelation(\Magento\Framework\Model\AbstractModel $object) { /** - * @var $object \Magento\Customer\Model\Address + * @var $object Address */ if (!$object->getIsCustomerSaveTransaction() && $object->getId()) { $customer = $this->customerFactory->create()->load($object->getCustomerId()); - $changedAddresses['default_billing'] = $this->getDefaultBillingChangedAddress($object, $customer); - $changedAddresses['default_shipping'] = $this->getDefaultShippingChangedAddress($object, $customer); + $changedAddresses = []; + $changedAddresses = $this->getDefaultBillingChangedAddress($object, $customer, $changedAddresses); + $changedAddresses = $this->getDefaultShippingChangedAddress($object, $customer, $changedAddresses); if ($changedAddresses) { $customer->getResource()->getConnection()->update( @@ -59,37 +60,49 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) /** * Get default billing changed address * - * @param AddressModelInterface $object + * @param Address $object * @param Customer $customer - * @return int|null + * @param array $changedAddresses + * @return array */ - private function getDefaultBillingChangedAddress(AddressModelInterface $object, Customer $customer): ?int - { + private function getDefaultBillingChangedAddress( + Address $object, + Customer $customer, + array $changedAddresses + ): array { if ($object->getIsDefaultBilling()) { - return $object->getId(); + $changedAddresses['default_billing'] = $object->getId(); } elseif ($customer->getDefaultBillingAddress() && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() ) { - return null; + $changedAddresses['default_billing'] = null; } + + return $changedAddresses; } /** * Get default shipping changed address * - * @param AddressModelInterface $object + * @param Address $object * @param Customer $customer - * @return int|null + * @param array $changedAddresses + * @return array */ - private function getDefaultShippingChangedAddress(AddressModelInterface $object, Customer $customer): ?int - { + private function getDefaultShippingChangedAddress( + Address $object, + Customer $customer, + array $changedAddresses + ): array { if ($object->getIsDefaultShipping()) { - return $object->getId(); + $changedAddresses['default_shipping'] = $object->getId(); } elseif ($customer->getDefaultShippingAddress() && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() ) { - return null; + $changedAddresses['default_shipping'] = null; } + + return $changedAddresses; } /** diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php index 20177ab0b0db6..8f8ed0e37a46b 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php @@ -70,7 +70,8 @@ protected function setUp() $this->context, $this->fileUploaderFactory, $this->addressMetadataService, - $this->logger + $this->logger, + 'address' ); } @@ -104,27 +105,27 @@ public function testExecuteEmptyFiles() public function testExecute() { - $attributeCode = 'attribute_code'; + $attributeCode = 'file_address_attribute'; + $resultFileSize = 20000; + $resultFileName = 'text.txt'; + $resultType = 'text/plain'; $_FILES = [ - 'address' => [ - 'name' => [ - 'new_0' => [ - $attributeCode => 'filename', - ], - ], + $attributeCode => [ + 'name' => $resultFileName, + 'type' => $resultType, + 'size' => $resultFileSize ], ]; - $resultFileName = '/filename.ext1'; $resultFilePath = 'filepath'; $resultFileUrl = 'viewFileUrl'; $result = [ 'name' => $resultFileName, - 'file' => $resultFileName, - 'path' => $resultFilePath, - 'tmp_name' => $resultFilePath . $resultFileName, + 'type' => $resultType, + 'size' => $resultFileSize, + 'tmp_name' => $resultFilePath . '/' . $resultFileName, 'url' => $resultFileUrl, ]; @@ -173,15 +174,16 @@ public function testExecute() public function testExecuteWithErrors() { - $attributeCode = 'attribute_code'; + $attributeCode = 'file_address_attribute'; + $resultFileSize = 20000; + $resultFileName = 'text.txt'; + $resultType = 'text/plain'; $_FILES = [ - 'address' => [ - 'name' => [ - 'new_0' => [ - $attributeCode => 'filename', - ], - ], + $attributeCode => [ + 'name' => $resultFileName, + 'type' => $resultType, + 'size' => $resultFileSize ], ]; diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php index e81637cfb23b2..319179c5e279a 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php @@ -6,6 +6,7 @@ namespace Magento\Customer\Test\Unit\Model\ResourceModel\Address; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Customer\Model\Address; /** * Class AddressTest @@ -40,7 +41,7 @@ protected function setUp() */ public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShipping) { - $addressModel = $this->createPartialMock(\Magento\Framework\Model\AbstractModel::class, [ + $addressModel = $this->createPartialMock(Address::class, [ '__wakeup', 'getId', 'getEntityTypeId', @@ -55,7 +56,17 @@ public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShi ]); $customerModel = $this->createPartialMock( \Magento\Customer\Model\Customer::class, - ['__wakeup', 'setDefaultBilling', 'setDefaultShipping', 'save', 'load', 'getResource', 'getId'] + [ + '__wakeup', + 'setDefaultBilling', + 'setDefaultShipping', + 'save', + 'load', + 'getResource', + 'getId', + 'getDefaultShippingAddress', + 'getDefaultBillingAddress' + ] ); $customerResource = $this->getMockForAbstractClass( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, @@ -88,6 +99,7 @@ public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShi $this->customerFactoryMock->expects($this->any()) ->method('create') ->willReturn($customerModel); + if ($addressId && ($isDefaultBilling || $isDefaultShipping)) { $customerId = 1; $customerResource->expects($this->exactly(2))->method('getConnection')->willReturn($connectionMock); From a5ac2dc694e4fa6224754e0a68936e252bd4c91c Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Thu, 1 Nov 2018 19:30:20 +0200 Subject: [PATCH 0428/1158] MAGETWO-96024: Invalid element declared for AdminProductGridSection section --- .../AdminProductGridActionGroup.xml | 23 +++++++++++++ .../Mftf/Section/AdminProductGridSection.xml | 1 + ...atusProductUsingProductGridActionGroup.xml | 33 ------------------- .../Mftf/Section/AdminProductGridSection.xml | 14 -------- 4 files changed, 24 insertions(+), 47 deletions(-) delete mode 100644 app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml delete mode 100644 app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml index 1bd9bb4a09c86..e17f9933cbcab 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml @@ -206,4 +206,27 @@ <conditionalClick selector="{{AdminProductGridTableHeaderSection.id('descend')}}" dependentSelector="{{AdminProductGridTableHeaderSection.id('ascend')}}" visible="false" stepKey="sortById"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> + + <!--Disabled a product by filtering grid and using change status action--> + <actionGroup name="ChangeStatusProductUsingProductGridActionGroup"> + <arguments> + <argument name="product"/> + <argument name="status" defaultValue="Enable" type="string" /> + </arguments> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> + <waitForPageLoad time="60" stepKey="waitForPageLoadInitial"/> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> + <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> + <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillProductSkuFilter"/> + <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/> + <see selector="{{AdminProductGridSection.productGridCell('1', 'SKU')}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> + <click selector="{{AdminProductGridSection.multicheckDropdown}}" stepKey="openMulticheckDropdown"/> + <click selector="{{AdminProductGridSection.multicheckOption('Select All')}}" stepKey="selectAllProductInFilteredGrid"/> + + <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickActionDropdown"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Change status')}}" stepKey="clickChangeStatusAction"/> + <click selector="{{AdminProductGridSection.changeStatus('status')}}" stepKey="clickChangeStatusDisabled" parameterized="true"/> + <see selector="{{AdminMessagesSection.success}}" userInput="A total of 1 record(s) have been updated." stepKey="seeSuccessMessage"/> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial2"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml index a7e20e22f1ddc..304cb621e5d9b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml @@ -29,5 +29,6 @@ <element name="productGridCheckboxOnRow" type="checkbox" selector="//*[@id='container']//tr[{{row}}]/td[1]//input" parameterized="true"/> <element name="productGridNameProduct" type="input" selector="//tbody//tr//td//div[contains(., '{{var1}}')]" parameterized="true" timeout="30"/> <element name="selectRowBasedOnName" type="input" selector="//td/div[text()='{{var1}}']" parameterized="true"/> + <element name="changeStatus" type="button" selector="//div[contains(@class,'admin__data-grid-header-row') and contains(@class, 'row')]//div[contains(@class, 'action-menu-item')]//ul/li/span[text() = '{{status}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml b/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml deleted file mode 100644 index dba4a94f3db2a..0000000000000 --- a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <!--Disabled a product by filtering grid and using change status action--> - <actionGroup name="ChangeStatusProductUsingProductGridActionGroup"> - <arguments> - <argument name="product"/> - <argument name="status" defaultValue="Enable" type="string" /> - </arguments> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> - <waitForPageLoad time="60" stepKey="waitForPageLoadInitial"/> - <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> - <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> - <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillProductSkuFilter"/> - <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/> - <see selector="{{AdminProductGridSection.productGridCell('1', 'SKU')}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> - <click selector="{{AdminProductGridSection.multicheckDropdown}}" stepKey="openMulticheckDropdown"/> - <click selector="{{AdminProductGridSection.multicheckOption('Select All')}}" stepKey="selectAllProductInFilteredGrid"/> - - <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickActionDropdown"/> - <click selector="{{AdminProductGridSection.bulkActionOption('Change status')}}" stepKey="clickChangeStatusAction"/> - <click selector="{{AdminProductGridSection.changeStatus('status')}}" stepKey="clickChangeStatusDisabled" parameterized="true"/> - <see selector="{{AdminMessagesSection.success}}" userInput="A total of 1 record(s) have been updated." stepKey="seeSuccessMessage"/> - <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial2"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml deleted file mode 100644 index 32ac73aca7c03..0000000000000 --- a/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="AdminProductGridSection"> - <element name="changeStatus" selector="//div[contains(@class,'admin__data-grid-header-row') and contains(@class, 'row')]//div[contains(@class, 'action-menu-item')]//ul/li/span[text() = '{{status}}']" stepKey="clickChangeStatus" parameterized="true"/> - </section> -</sections> From 2533e88aea6e5834f632ff631e5a4cce6e1496b0 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Thu, 1 Nov 2018 16:27:20 -0500 Subject: [PATCH 0429/1158] MAGETWO-95773: Credit memo is created instead of returning error via invoice refund API for Bundle product - Update unit test coverage to include changed functionality --- .../Unit/Model/Order/ItemRepositoryTest.php | 94 ++++++++++++------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php index 5e1b49c0013e3..7f3626c25d8df 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php @@ -145,7 +145,7 @@ public function testGetEmptyEntity() $model->get($orderItemId); } - public function testGet() + public function testGetAsParentWithChild() { $orderItemId = 1; $productType = 'configurable'; @@ -154,18 +154,27 @@ public function testGet() $this->getProductOptionExtensionMock(); $productOption = $this->getProductOptionMock(); - $orderItemMock = $this->getOrderMock($productType, $productOption); + $orderItemMock = $this->getOrderItemMock($productType, $productOption); + + $orderItemCollectionMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Item\Collection::class); + $orderItemCollectionMock->expects($this->once()) + ->method('filterByParent') + ->with($orderItemId) + ->willReturnSelf(); + $orderItemCollectionMock->expects($this->once()) + ->method('getItems') + ->willReturn([$orderItemMock]); $orderMock = $this->createMock(\Magento\Sales\Model\Order::class); $orderMock->expects($this->once()) - ->method('getAllItems') - ->willReturn([$orderItemMock]); + ->method('getItemsCollection') + ->willReturn($orderItemCollectionMock); $orderItemMock->expects($this->once()) ->method('load') ->with($orderItemId) ->willReturn($orderItemMock); - $orderItemMock->expects($this->exactly(2)) + $orderItemMock->expects($this->exactly(3)) ->method('getItemId') ->willReturn($orderItemId); $orderItemMock->expects($this->once()) @@ -183,6 +192,45 @@ public function testGet() $this->assertSame($orderItemMock, $model->get($orderItemId)); } + public function testGetAsChild() + { + $orderItemId = 1; + $parentItemId = 66; + $productType = 'configurable'; + + $this->productOptionData = ['option1' => 'value1']; + + $this->getProductOptionExtensionMock(); + $productOption = $this->getProductOptionMock(); + $orderItemMock = $this->getOrderItemMock($productType, $productOption); + + $orderItemMock->expects($this->once()) + ->method('load') + ->with($orderItemId) + ->willReturn($orderItemMock); + $orderItemMock->expects($this->once()) + ->method('getItemId') + ->willReturn($orderItemId); + $orderItemMock->expects($this->exactly(3)) + ->method('getParentItemId') + ->willReturn($parentItemId); + + $this->metadata->expects($this->once()) + ->method('getNewInstance') + ->willReturn($orderItemMock); + + $parentItemMock = $this->createMock(\Magento\Sales\Model\Order\Item::class); + + $model = $this->getModel($orderItemMock, $productType); + $reflectedRegistryProperty = new \ReflectionProperty($model, 'registry'); + $reflectedRegistryProperty->setAccessible(true); + $reflectedRegistryProperty->setValue($model, [$parentItemId => $parentItemMock]); + $this->assertSame($orderItemMock, $model->get($orderItemId)); + + // Assert already registered + $this->assertSame($orderItemMock, $model->get($orderItemId)); + } + public function testGetList() { $productType = 'configurable'; @@ -192,7 +240,7 @@ public function testGetList() ->getMock(); $this->getProductOptionExtensionMock(); $productOption = $this->getProductOptionMock(); - $orderItemMock = $this->getOrderMock($productType, $productOption); + $orderItemMock = $this->getOrderItemMock($productType, $productOption); $searchResultMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Item\Collection::class) ->disableOriginalConstructor() @@ -214,35 +262,12 @@ public function testDeleteById() $orderItemId = 1; $productType = 'configurable'; - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) ->disableOriginalConstructor() ->getMock(); - - $orderMock = $this->createMock(\Magento\Sales\Model\Order::class); - $orderMock->expects($this->once()) - ->method('getAllItems') - ->willReturn([$orderItemMock]); - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->exactly(2)) - ->method('getItemId') + ->method('getEntityId') ->willReturn($orderItemId); - $orderItemMock->expects($this->once()) - ->method('getProductType') - ->willReturn($productType); - $orderItemMock->expects($this->once()) - ->method('getBuyRequest') - ->willReturn($requestMock); - $orderItemMock->expects($this->once()) - ->method('getOrder') - ->willReturn($orderMock); $orderItemResourceMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) ->disableOriginalConstructor() @@ -252,15 +277,16 @@ public function testDeleteById() ->with($orderItemMock) ->willReturnSelf(); - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); $this->metadata->expects($this->exactly(1)) ->method('getMapper') ->willReturn($orderItemResourceMock); $model = $this->getModel($orderItemMock, $productType); + $reflectedRegistryProperty = new \ReflectionProperty($model, 'registry'); + $reflectedRegistryProperty->setAccessible(true); + $reflectedRegistryProperty->setValue($model, [$orderItemId => $orderItemMock]); $this->assertTrue($model->deleteById($orderItemId)); + $this->assertEmpty($reflectedRegistryProperty->getValue($model)); } /** @@ -318,7 +344,7 @@ protected function getModel( * @param \PHPUnit_Framework_MockObject_MockObject $productOption * @return \PHPUnit_Framework_MockObject_MockObject */ - protected function getOrderMock($productType, $productOption) + protected function getOrderItemMock($productType, $productOption) { $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() From cbf828a00a9a2287d7c7bb640f3c1078410b4de4 Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Wed, 24 Oct 2018 20:55:30 -0400 Subject: [PATCH 0430/1158] Separate interception config logic Moves the logic responsible for loading, saving, clearing the interception config cache into it's own class --- app/etc/di.xml | 6 + .../Framework/Interception/AbstractPlugin.php | 8 +- .../{ConfigTest.php => CacheManagerTest.php} | 15 +-- .../Interception/Config/CacheManager.php | 113 ++++++++++++++++++ .../Framework/Interception/Config/Config.php | 71 +++-------- .../Test/Unit/Config/ConfigTest.php | 42 ++----- 6 files changed, 157 insertions(+), 98 deletions(-) rename dev/tests/integration/testsuite/Magento/Framework/Interception/Config/{ConfigTest.php => CacheManagerTest.php} (87%) create mode 100644 lib/internal/Magento/Framework/Interception/Config/CacheManager.php diff --git a/app/etc/di.xml b/app/etc/di.xml index b374645240ff7..acdd48a393b5e 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -28,6 +28,7 @@ <preference for="Magento\Framework\App\CacheInterface" type="Magento\Framework\App\Cache\Proxy" /> <preference for="Magento\Framework\App\Cache\StateInterface" type="Magento\Framework\App\Cache\State" /> <preference for="Magento\Framework\App\Cache\TypeListInterface" type="Magento\Framework\App\Cache\TypeList" /> + <preference for="Magento\Framework\App\ObjectManager\ConfigWriterInterface" type="Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem" /> <preference for="Magento\Store\Model\StoreManagerInterface" type="Magento\Store\Model\StoreManager" /> <preference for="Magento\Framework\View\DesignInterface" type="Magento\Theme\Model\View\Design\Proxy" /> <preference for="Magento\Framework\View\Design\ThemeInterface" type="Magento\Theme\Model\Theme" /> @@ -412,6 +413,11 @@ <argument name="cacheId" xsi:type="string">interception</argument> </arguments> </type> + <type name="Magento\Framework\Interception\Config\CacheManager"> + <arguments> + <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Config</argument> + </arguments> + </type> <type name="Magento\Framework\Interception\PluginList\PluginList"> <arguments> <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Config</argument> diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php index a85e5e7c89482..60eb511dcb6b5 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php @@ -59,7 +59,8 @@ public function setUpInterceptionConfig($pluginConfig) $areaList->expects($this->any())->method('getCodes')->will($this->returnValue([])); $configScope = new \Magento\Framework\Config\Scope($areaList, 'global'); $cache = $this->createMock(\Magento\Framework\Config\CacheInterface::class); - $cache->expects($this->any())->method('load')->will($this->returnValue(false)); + $cacheManager = $this->createMock(\Magento\Framework\Interception\Config\CacheManager::class); + $cacheManager->method('load')->willReturn(null); $definitions = new \Magento\Framework\ObjectManager\Definition\Runtime(); $relations = new \Magento\Framework\ObjectManager\Relations\Runtime(); $interceptionConfig = new Config\Config( @@ -68,7 +69,10 @@ public function setUpInterceptionConfig($pluginConfig) $cache, $relations, $config, - $definitions + $definitions, + 'interception', + null, + $cacheManager ); $interceptionDefinitions = new Definition\Runtime(); $json = new \Magento\Framework\Serialize\Serializer\Json(); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php similarity index 87% rename from dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php rename to dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php index 1ece9189169bb..9d5abd1a8a6c6 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php @@ -10,7 +10,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; -class ConfigTest extends \PHPUnit\Framework\TestCase +class CacheManagerTest extends \PHPUnit\Framework\TestCase { const CACHE_ID = 'interceptiontest'; @@ -68,9 +68,7 @@ public function testInstantiateFromCompiled(array $testConfig) $this->configWriter->write(self::CACHE_ID, $testConfig); $config = $this->getConfig(); - foreach ($testConfig as $className => $hasPlugins) { - $this->assertEquals($hasPlugins, $config->hasPlugins($className)); - } + $this->assertEquals($testConfig, $config->load(self::CACHE_ID)); } /** @@ -83,9 +81,7 @@ public function testInstantiateFromCache(array $testConfig) $this->cache->save($this->serializer->serialize($testConfig), self::CACHE_ID); $config = $this->getConfig(); - foreach ($testConfig as $className => $hasPlugins) { - $this->assertEquals($hasPlugins, $config->hasPlugins($className)); - } + $this->assertEquals($testConfig, $config->load(self::CACHE_ID)); } public function interceptionCompiledConfigDataProvider() @@ -121,16 +117,15 @@ private function initializeMetadataDirectory() * from altering the interception config that may have been generated during application * installation. Inject a new instance of the compileLoaded to bypass it's caching. * - * @return \Magento\Framework\Interception\Config\Config + * @return \Magento\Framework\Interception\Config\CacheManager */ private function getConfig() { return $this->objectManager->create( - \Magento\Framework\Interception\Config\Config::class, + \Magento\Framework\Interception\Config\CacheManager::class, [ 'cacheId' => self::CACHE_ID, 'compiledLoader' => $this->objectManager->create(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class), - 'serializer' => $this->serializer, ] ); } diff --git a/lib/internal/Magento/Framework/Interception/Config/CacheManager.php b/lib/internal/Magento/Framework/Interception/Config/CacheManager.php new file mode 100644 index 0000000000000..cd16e2277d87a --- /dev/null +++ b/lib/internal/Magento/Framework/Interception/Config/CacheManager.php @@ -0,0 +1,113 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\Interception\Config; + +/** + * Interception cache manager responsible for handling interaction with compiled and + * uncompiled interception data + */ +class CacheManager +{ + /** + * @var \Magento\Framework\Cache\FrontendInterface + */ + private $cache; + + /** + * @var \Magento\Framework\Serialize\SerializerInterface + */ + private $serializer; + + /** + * @var \Magento\Framework\App\ObjectManager\ConfigWriterInterface + */ + private $configWriter; + + /** + * @var \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled + */ + private $compiledLoader; + + /** + * @param \Magento\Framework\Cache\FrontendInterface $cache + * @param \Magento\Framework\Serialize\SerializerInterface $serializer + * @param \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter + * @param \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader + */ + public function __construct( + \Magento\Framework\Cache\FrontendInterface $cache, + \Magento\Framework\Serialize\SerializerInterface $serializer, + \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter, + \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader + ) { + $this->cache = $cache; + $this->serializer = $serializer; + $this->configWriter = $configWriter; + $this->compiledLoader = $compiledLoader; + } + + /** + * Load the interception config from cache + * + * @param string $key + * @return array|null + */ + public function load(string $key): ?array + { + if ($this->isCompiled($key)) { + return $this->compiledLoader->load($key); + } + + $intercepted = $this->cache->load($key); + return $intercepted ? $this->serializer->unserialize($intercepted) : null; + } + + /** + * Save config to cache backend + * + * @param string $key + * @param array $data + */ + public function save(string $key, array $data) + { + $this->cache->save($this->serializer->serialize($data), $key); + } + + /** + * Save config to filesystem + * + * @param string $key + * @param array $data + */ + public function saveCompiled(string $key, array $data) + { + $this->configWriter->write($key, $data); + } + + /** + * Purge interception cache + * + * @param string $key + */ + public function clean(string $key) + { + $this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [$key]); + } + + /** + * Check for the compiled config with the generated metadata + * + * @param string $key + * @return bool + */ + private function isCompiled(string $key): bool + { + return file_exists(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::getFilePath($key)); + } +} diff --git a/lib/internal/Magento/Framework/Interception/Config/Config.php b/lib/internal/Magento/Framework/Interception/Config/Config.php index 9a7845e96006b..4eeed4788a05e 100644 --- a/lib/internal/Magento/Framework/Interception/Config/Config.php +++ b/lib/internal/Magento/Framework/Interception/Config/Config.php @@ -8,7 +8,6 @@ namespace Magento\Framework\Interception\Config; use Magento\Framework\Serialize\SerializerInterface; -use Magento\Framework\Serialize\Serializer\Serialize; class Config implements \Magento\Framework\Interception\ConfigInterface { @@ -35,7 +34,7 @@ class Config implements \Magento\Framework\Interception\ConfigInterface /** * Cache - * + * @deprecated * @var \Magento\Framework\Cache\FrontendInterface */ protected $_cache; @@ -74,33 +73,24 @@ class Config implements \Magento\Framework\Interception\ConfigInterface protected $_scopeList; /** - * @var SerializerInterface - */ - private $serializer; - - /** - * @var \Magento\Framework\App\ObjectManager\ConfigWriterInterface - */ - private $configWriter; - - /** - * @var \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled + * @var CacheManager */ - private $compiledLoader; + private $cacheManager; /** * Config constructor * * @param \Magento\Framework\Config\ReaderInterface $reader * @param \Magento\Framework\Config\ScopeListInterface $scopeList - * @param \Magento\Framework\Cache\FrontendInterface $cache + * @param \Magento\Framework\Cache\FrontendInterface $cache @deprecated * @param \Magento\Framework\ObjectManager\RelationsInterface $relations * @param \Magento\Framework\Interception\ObjectManager\ConfigInterface $omConfig * @param \Magento\Framework\ObjectManager\DefinitionInterface $classDefinitions * @param string $cacheId - * @param SerializerInterface|null $serializer - * @param \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter - * @param \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader + * @param SerializerInterface|null $serializer @deprecated + * @param CacheManager $cacheManager + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( \Magento\Framework\Config\ReaderInterface $reader, @@ -111,8 +101,7 @@ public function __construct( \Magento\Framework\ObjectManager\DefinitionInterface $classDefinitions, $cacheId = 'interception', SerializerInterface $serializer = null, - \Magento\Framework\App\ObjectManager\ConfigWriterInterface $configWriter = null, - \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled $compiledLoader = null + CacheManager $cacheManager = null ) { $this->_omConfig = $omConfig; $this->_relations = $relations; @@ -121,14 +110,9 @@ public function __construct( $this->_cacheId = $cacheId; $this->_reader = $reader; $this->_scopeList = $scopeList; - $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() - ->get(Serialize::class); - $this->configWriter = $configWriter ?: \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); - $this->compiledLoader = $compiledLoader ?: \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class); - $intercepted = $this->loadIntercepted(); - if ($intercepted !== false) { + $this->cacheManager = $cacheManager ?? \Magento\Framework\App\ObjectManager::getInstance()->get(CacheManager::class); + $intercepted = $this->cacheManager->load($cacheId); + if ($intercepted !== null) { $this->_intercepted = $intercepted; } else { $this->initializeUncompiled($this->_classDefinitions->getClasses()); @@ -145,7 +129,7 @@ public function initialize($classDefinitions = []) { $this->generateIntercepted($classDefinitions); - $this->configWriter->write($this->_cacheId, $this->_intercepted); + $this->cacheManager->saveCompiled($this->_cacheId, $this->_intercepted); } /** @@ -199,11 +183,11 @@ public function hasPlugins($type) */ private function initializeUncompiled($classDefinitions = []) { - $this->_cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [$this->_cacheId]); + $this->cacheManager->clean($this->_cacheId); $this->generateIntercepted($classDefinitions); - $this->_cache->save($this->serializer->serialize($this->_intercepted), $this->_cacheId); + $this->cacheManager->save($this->_cacheId, $this->_intercepted); } /** @@ -230,29 +214,4 @@ private function generateIntercepted($classDefinitions) $this->hasPlugins($class); } } - - /** - * Load the interception config from cache - * - * @return array|false - */ - private function loadIntercepted() - { - if ($this->isCompiled()) { - return $this->compiledLoader->load($this->_cacheId); - } - - $intercepted = $this->_cache->load($this->_cacheId); - return $intercepted ? $this->serializer->unserialize($intercepted) : false; - } - - /** - * Check for the compiled config with the generated metadata - * - * @return bool - */ - private function isCompiled() - { - return file_exists(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::getFilePath($this->_cacheId)); - } } diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Config/ConfigTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Config/ConfigTest.php index fe8d29bd0d51d..61eb2e62091ea 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/Config/ConfigTest.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Config/ConfigTest.php @@ -31,11 +31,6 @@ class ConfigTest extends \PHPUnit\Framework\TestCase */ private $readerMock; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $cacheMock; - /** * @var \PHPUnit_Framework_MockObject_MockObject */ @@ -51,8 +46,10 @@ class ConfigTest extends \PHPUnit\Framework\TestCase */ private $relationsMock; - /** @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $serializerMock; + /** + * @var \Magento\Framework\Interception\Config\CacheManager|\PHPUnit_Framework_MockObject_MockObject + */ + private $cacheManagerMock; /** @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ private $objectManagerHelper; @@ -61,7 +58,6 @@ protected function setUp() { $this->readerMock = $this->createMock(\Magento\Framework\ObjectManager\Config\Reader\Dom::class); $this->configScopeMock = $this->createMock(\Magento\Framework\Config\ScopeListInterface::class); - $this->cacheMock = $this->createMock(\Magento\Framework\Cache\FrontendInterface::class); $this->omConfigMock = $this->getMockForAbstractClass( \Magento\Framework\Interception\ObjectManager\ConfigInterface::class ); @@ -69,7 +65,7 @@ protected function setUp() $this->relationsMock = $this->getMockForAbstractClass( \Magento\Framework\ObjectManager\RelationsInterface::class ); - $this->serializerMock = $this->createMock(SerializerInterface::class); + $this->cacheManagerMock = $this->createMock(\Magento\Framework\Interception\Config\CacheManager::class); $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); } @@ -88,9 +84,9 @@ public function testHasPluginsWhenDataIsNotCached($expectedResult, $type, $entit ->method('getAllScopes') ->will($this->returnValue(['global', 'backend', 'frontend'])); // turn cache off - $this->cacheMock->expects($this->any()) + $this->cacheManagerMock->expects($this->any()) ->method('load') - ->will($this->returnValue(false)); + ->will($this->returnValue(null)); $this->omConfigMock->expects($this->any()) ->method('getOriginalInstanceType') ->will($this->returnValueMap( @@ -138,21 +134,15 @@ public function testHasPluginsWhenDataIsNotCached($expectedResult, $type, $entit $this->relationsMock->expects($this->any())->method('has')->will($this->returnValue($expectedResult)); $this->relationsMock->expects($this->any())->method('getParents')->will($this->returnValue($entityParents)); - $this->serializerMock->expects($this->once()) - ->method('serialize'); - - $this->serializerMock->expects($this->never())->method('unserialize'); - $model = $this->objectManagerHelper->getObject( \Magento\Framework\Interception\Config\Config::class, [ 'reader' => $this->readerMock, 'scopeList' => $this->configScopeMock, - 'cache' => $this->cacheMock, + 'cacheManager' => $this->cacheManagerMock, 'relations' => $this->relationsMock, 'omConfig' => $this->omConfigMock, 'classDefinitions' => $this->definitionMock, - 'serializer' => $this->serializerMock ] ); @@ -177,32 +167,24 @@ public function testHasPluginsWhenDataIsCached($expectedResult, $type) 'virtual_custom_item' => true ]; $this->readerMock->expects($this->never())->method('read'); - $this->cacheMock->expects($this->never())->method('save'); - $serializedValue = 'serializedData'; - $this->cacheMock->expects($this->any()) + $this->cacheManagerMock->expects($this->never())->method('save'); + $this->cacheManagerMock->expects($this->any()) ->method('load') ->with($cacheId) - ->will($this->returnValue($serializedValue)); - - $this->serializerMock->expects($this->never())->method('serialize'); - $this->serializerMock->expects($this->once()) - ->method('unserialize') - ->with($serializedValue) - ->willReturn($interceptionData); + ->will($this->returnValue($interceptionData)); $model = $this->objectManagerHelper->getObject( \Magento\Framework\Interception\Config\Config::class, [ 'reader' => $this->readerMock, 'scopeList' => $this->configScopeMock, - 'cache' => $this->cacheMock, + 'cacheManager' => $this->cacheManagerMock, 'relations' => $this->objectManagerHelper->getObject( \Magento\Framework\ObjectManager\Relations\Runtime::class ), 'omConfig' => $this->omConfigMock, 'classDefinitions' => $this->definitionMock, 'cacheId' => $cacheId, - 'serializer' => $this->serializerMock ] ); From fc5eb486c48c3c6fd709d2a042b101e0bf32c976 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Fri, 2 Nov 2018 10:39:49 +0200 Subject: [PATCH 0431/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Index in db_schema.xml fixed --- app/code/Magento/Customer/etc/db_schema.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index 7e0b911e26184..7cf4c5be641e8 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -120,8 +120,8 @@ <index referenceId="CUSTOMER_ADDRESS_ENTITY_PARENT_ID" indexType="btree"> <column name="parent_id"/> </index> - <index name="CUSTOMER_ADDRESS_ENTITY_FULLTEXT_INDEX" indexType="fulltext"> - <column name="firstname"/> + <index referenceId="CUSTOMER_ADDRESS_ENTITY_FULLTEXT_INDEX" indexType="fulltext"> + <column name="firstname"/> <column name="lastname"/> <column name="street"/> <column name="city"/> From ea661055fc94c1f5a3c7399463915491acc8c0a5 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Fri, 2 Nov 2018 11:41:20 +0300 Subject: [PATCH 0432/1158] MAGETWO-70303: [GITHUB] Anchor categories are showing products of disabled subcategories #9002 - Fix comments --- .../Catalog/Model/Indexer/Category/Product/AbstractAction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index a1358c02ce9fc..178f4172ce6fa 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -605,7 +605,7 @@ protected function getTemporaryTreeIndexTableName() if (empty($this->tempTreeIndexTableName)) { $this->tempTreeIndexTableName = $this->connection->getTableName('temp_catalog_category_tree_index') . '_' - . substr(md5(time() . random_int(0, 999999999)), 0, 8); + . substr(sha1(time() . random_int(0, 999999999)), 0, 8); } return $this->tempTreeIndexTableName; From 480aa38783f28951ed10f16177aaf3f295818f9e Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Fri, 2 Nov 2018 11:53:15 +0300 Subject: [PATCH 0433/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fix comments --- .../Magento/Catalog/Block/Product/ProductList/Toolbar.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index c7a9fcce7bf7a..a2cbc5087cd12 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -161,10 +161,10 @@ public function __construct( \Magento\Framework\Url\EncoderInterface $urlEncoder, ProductList $productListHelper, \Magento\Framework\Data\Helper\PostHelper $postDataHelper, + array $data = [], ToolbarMemorizer $toolbarMemorizer = null, \Magento\Framework\App\Http\Context $httpContext = null, - \Magento\Framework\Data\Form\FormKey $formKey = null, - array $data = [] + \Magento\Framework\Data\Form\FormKey $formKey = null ) { $this->_catalogSession = $catalogSession; $this->_catalogConfig = $catalogConfig; From 71e6f40b1c00b55fd59694ad040749ea26ebbb97 Mon Sep 17 00:00:00 2001 From: Alexandr Voronoy <servermed@gmail.com> Date: Fri, 2 Nov 2018 11:31:20 +0200 Subject: [PATCH 0434/1158] Removed method annotation without argument from PHPDoc --- app/code/Magento/Backend/Block/Widget/Grid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Backend/Block/Widget/Grid.php b/app/code/Magento/Backend/Block/Widget/Grid.php index 72ab5a265d808..e9394be9e60bd 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid.php +++ b/app/code/Magento/Backend/Block/Widget/Grid.php @@ -12,7 +12,7 @@ * @api * @deprecated 100.2.0 in favour of UI component implementation * @method string getRowClickCallback() getRowClickCallback() - * @method \Magento\Backend\Block\Widget\Grid setRowClickCallback() setRowClickCallback(string $value) + * @method \Magento\Backend\Block\Widget\Grid setRowClickCallback(string $value) * @SuppressWarnings(PHPMD.TooManyFields) * @since 100.0.2 */ From 0cf59de0e706b213e836949700a713fdfa9cf4f4 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 2 Nov 2018 11:33:02 +0200 Subject: [PATCH 0435/1158] Added user permission check --- .../Model/Resolver/CartAddress.php | 30 +++++++++++++++---- .../SetShippingMethodsOnCart.php | 8 +++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php index f83a112ba5ba8..d2b502688adbc 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php @@ -10,11 +10,13 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteId; +use Magento\QuoteGraphQl\Model\Authorization\IsCartMutationAllowedForCurrentUser; use Magento\QuoteGraphQl\Model\Resolver\Address\AddressDataProvider; /** @@ -27,6 +29,11 @@ class CartAddress implements ResolverInterface */ private $addressDataProvider; + /** + * @var IsCartMutationAllowedForCurrentUser + */ + private $isCartMutationAllowedForCurrentUser; + /** * @var CartRepositoryInterface */ @@ -43,15 +50,18 @@ class CartAddress implements ResolverInterface * @param MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId * @param CartRepositoryInterface $cartRepository * @param AddressDataProvider $addressDataProvider + * @param IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser */ public function __construct( MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId, CartRepositoryInterface $cartRepository, - AddressDataProvider $addressDataProvider + AddressDataProvider $addressDataProvider, + IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser ) { $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->cartRepository = $cartRepository; $this->addressDataProvider = $addressDataProvider; + $this->isCartMutationAllowedForCurrentUser = $isCartMutationAllowedForCurrentUser; } /** @@ -59,20 +69,30 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { + /* The cart_id is used instead of the model because some parent resolvers do not work + with cart model */ if (!isset($value['cart_id'])) { - // TODO: consider the possibility to pass quote model instead od quote ID throw new LocalizedException(__('"cart_id" value should be specified')); } + $maskedCartId = $value['cart_id']; + try { - $quoteId = $this->maskedQuoteIdToQuoteId->execute($value['cart_id']); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); } catch (NoSuchEntityException $exception) { throw new GraphQlNoSuchEntityException( - __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $value['cart_id']]) + __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $maskedCartId]) ); } - // TODO: should we check customer permissions here as well? + if (false === $this->isCartMutationAllowedForCurrentUser->execute($quoteId)) { + throw new GraphQlAuthorizationException( + __( + 'The current user cannot perform operations on cart "%masked_cart_id"', + ['masked_cart_id' => $maskedCartId] + ) + ); + } try { $quote = $this->cartRepository->get($quoteId); diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php index 1f35f37d9cf23..7e35f97d9f711 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php @@ -72,13 +72,17 @@ class SetShippingMethodsOnCart implements ResolverInterface * @param ArrayManager $arrayManager * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser + * @param ShippingInformationManagementInterface $shippingInformationManagement + * @param QuoteAddressFactory $quoteAddressFactory + * @param QuoteAddressResource $quoteAddressResource + * @param ShippingInformationFactory $shippingInformationFactory */ public function __construct( ArrayManager $arrayManager, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser, ShippingInformationManagementInterface $shippingInformationManagement, - QuoteAddressFactory $quoteAddressFacrory, + QuoteAddressFactory $quoteAddressFactory, QuoteAddressResource $quoteAddressResource, ShippingInformationFactory $shippingInformationFactory ) { @@ -88,7 +92,7 @@ public function __construct( $this->shippingInformationManagement = $shippingInformationManagement; $this->quoteAddressResource = $quoteAddressResource; - $this->quoteAddressFactory = $quoteAddressFacrory; + $this->quoteAddressFactory = $quoteAddressFactory; $this->shippingInformationFactory = $shippingInformationFactory; } From 8b921165cc562d5fd8fafb0126aea66080eeb8ef Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Fri, 2 Nov 2018 12:44:03 +0300 Subject: [PATCH 0436/1158] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Remove atomation test --- .../Test/Mftf/Data/AuthorizenetData.xml | 95 ------------------- .../Mftf/Metadata/authorize-config-meta.xml | 79 --------------- .../AuthorizenetConfiguraionSection.xml | 19 ---- .../AuthorizenetCreditCardInformationTest.xml | 81 ---------------- 4 files changed, 274 deletions(-) delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml b/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml deleted file mode 100644 index c4f59ba03bf22..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="AuthorizenetConfig" type="authorize_net_config"> - <requiredEntity type="active">Active</requiredEntity> - <requiredEntity type="login">LoginId</requiredEntity> - <requiredEntity type="trans_key">TransactionKey</requiredEntity> - <requiredEntity type="trans_md5">TransMD5</requiredEntity> - <requiredEntity type="test">TestMode</requiredEntity> - <requiredEntity type="useccv">CVVVerification</requiredEntity> - <requiredEntity type="cgi_url">CGI_UTL</requiredEntity> - <requiredEntity type="cgi_url_td">CGI_URL_TD</requiredEntity> - <requiredEntity type="debug">Debug</requiredEntity> - </entity> - <entity name="Active" type="active"> - <data key="value">1</data> - </entity> - <entity name="LoginId" type="login"> - <data key="value">4By5Q8m6</data> - </entity> - <entity name="TransactionKey" type="trans_key"> - <data key="value">9pygB4X4n783TJbw</data> - </entity> - <entity name="TransMD5" type="trans_md5"> - <data key="value">Md5Hash</data> - </entity> - <entity name="TestMode" type="test"> - <data key="value">0</data> - </entity> - <entity name="CVVVerification" type="useccv"> - <data key="value">1</data> - </entity> - <entity name="CGI_UTL" type="cgi_url"> - <data key="value">https://test.authorize.net/gateway/transact.dll</data> - </entity> - <entity name="CGI_URL_TD" type="cgi_url_td"> - <data key="value">https://apitest.authorize.net/xml/v1/request.api</data> - </entity> - <entity name="Debug" type="debug"> - <data key="value">1</data> - </entity> - - <entity name="AuthorizenetDefaultConfig" type="authorize_net_config"> - <requiredEntity type="active">DefaultActive</requiredEntity> - <requiredEntity type="trans_key">DefaultTransactionKey</requiredEntity> - <requiredEntity type="trans_md5">DefaultTransMD5</requiredEntity> - <requiredEntity type="test">DefaultTestMode</requiredEntity> - <requiredEntity type="useccv">DefaultCVVVerification</requiredEntity> - <requiredEntity type="cgi_url">DefaultCGI_UTL</requiredEntity> - <requiredEntity type="cgi_url_td">DefaultCGI_URL_TD</requiredEntity> - <requiredEntity type="debug">DefaultDebugMode</requiredEntity> - </entity> - <entity name="DefaultDebug" type="debug"> - <data key="value">0</data> - </entity> - <entity name="DefaultActive" type="active"> - <data key="value">0</data> - </entity> - <entity name="DefaultLoginId" type="login"> - <data key="value"></data> - </entity> - <entity name="DefaultTransactionKey" type="trans_key"> - <data key="value"></data> - </entity> - <entity name="DefaultTransMD5" type="trans_md5"> - <data key="value"></data> - </entity> - <entity name="DefaultTestMode" type="test"> - <data key="value">1</data> - </entity> - <entity name="DefaultCVVVerification" type="useccv"> - <data key="value">0</data> - </entity> - <entity name="DefaultCGI_UTL" type="cgi_url"> - <data key="value">https://secure.authorize.net/gateway/transact.dll</data> - </entity> - <entity name="DefaultCGI_URL_TD" type="cgi_url_td"> - <data key="value">https://api2.authorize.net/xml/v1/request.api</data> - </entity> - - <entity name="DisableAuthorizenetConfig" type="authorize_net_config"> - <requiredEntity type="disableConfig">DisableConfig</requiredEntity> - </entity> - - <entity name="DisableConfig" type="disableConfig"> - <data key="value">0</data> - </entity> -</entities> diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml b/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml deleted file mode 100644 index ca9bbdad00870..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml +++ /dev/null @@ -1,79 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> - <operation name="AuthorizeNetConfig" dataType="authorize_net_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST"> - <object key="groups" dataType="authorize_net_config"> - <object key="authorizenet_directpost" dataType="authorize_net_config"> - <object key="fields" dataType="authorize_net_config"> - <object key="active" dataType="active"> - <field key="value">integer</field> - </object> - <object key="login" dataType="login"> - <field key="value">string</field> - </object> - <object key="trans_key" dataType="trans_key"> - <field key="value">string</field> - </object> - <object key="trans_md5" dataType="trans_md5"> - <field key="value">string</field> - </object> - <object key="test" dataType="test"> - <field key="value">string</field> - </object> - <object key="useccv" dataType="useccv"> - <field key="value">string</field> - </object> - <object key="cgi_url" dataType="cgi_url"> - <field key="value">string</field> - </object> - <object key="cgi_url_td" dataType="cgi_url_td"> - <field key="value">string</field> - </object> - <object key="debug" dataType="debug"> - <field key="value">string</field> - </object> - </object> - </object> - </object> - </operation> - - <operation name="AuthorizeNetDefaultConfig" dataType="authorize_net_default_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST"> - <object key="groups" dataType="authorize_net_default_config"> - <object key="authorizenet_directpost" dataType="authorize_net_default_config"> - <object key="fields" dataType="authorize_net_default_config"> - <object key="active" dataType="authorize_net_default_config"> - <object key="inherit" dataType="disableActive"> - <field key="value">integer</field> - </object> - </object> - <object key="test" dataType="authorize_net_default_config"> - <object key="inherit" dataType="disableConfig"> - <field key="value">integer</field> - </object> - </object> - <object key="cgi_url" dataType="authorize_net_default_config"> - <object key="inherit" dataType="disableConfig"> - <field key="value">integer</field> - </object> - </object> - <object key="cgi_url_td" dataType="authorize_net_default_config"> - <object key="inherit" dataType="disableConfig"> - <field key="value">integer</field> - </object> - </object> - <object key="debug" dataType="authorize_net_default_config"> - <object key="inherit" dataType="disableConfig"> - <field key="value">integer</field> - </object> - </object> - </object> - </object> - </object> - </operation> -</operations> diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml b/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml deleted file mode 100644 index 5d4f6c3f9819a..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="AuthorizenetConfigurationSection"> - <element name="paymentMethod" type="input" selector="#p_method_authorizenet_directpost"/> - <element name="cardType" type="select" selector="#authorizenet_directpost_cc_type"/> - <element name="cardNumber" type="input" selector="#authorizenet_directpost_cc_number"/> - <element name="month" type="select" selector="#authorizenet_directpost_expiration"/> - <element name="year" type="select" selector="#authorizenet_directpost_expiration_yr"/> - <element name="afterTwoYear" type="select" selector="//*[@id='authorizenet_directpost_expiration_yr']/option[4]"/> - <element name="verificationNumber" type="input" selector="#authorizenet_directpost_cc_cid"/> - </section> -</sections> diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml b/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml deleted file mode 100644 index b5d0b6079bb8b..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AuthorizenetCreditCardInformationTest"> - <annotations> - <features value="Authorizenet"/> - <stories value="MAGETWO-91526 - Authorize.net Direct Post does not show credit card information"/> - <title value="Checking credit card information of Authorize.net Direct Post"/> - <description value="Checking credit card information of Authorize.net Direct Post"/> - <severity value="MAJOR"/> - <testCaseId value="MAGETWO-91526"/> - <group value="Authorizenet"/> - </annotations> - - <before> - <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="SimpleProduct" stepKey="createProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> - <createData stepKey="setConfig" entity="AuthorizenetConfig"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> - <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> - </before> - <after> - <actionGroup ref="logout" stepKey="logout"/> - <deleteData createDataKey="createCategory" stepKey="deleteProduct"/> - <deleteData createDataKey="createProduct" stepKey="deleteCategory"/> - <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> - <createData stepKey="setDefaultConfig" entity="AuthorizenetDefaultConfig"/> - <createData stepKey="DisableConfigValues" entity="DisableAuthorizenetConfig"/> - </after> - <!--Create new order--> - <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="CreateNewOrder"> - <argument name="customer" value="Simple_US_Customer_NY"/> - </actionGroup> - <!--Add product to order--> - <click selector="{{OrdersGridSection.addProducts}}" stepKey="clickToAddProduct"/> - <waitForPageLoad stepKey="waitForProductsOpened"/> - <click selector="{{OrdersGridSection.selectProduct($$createProduct.name$$)}}" stepKey="selectProduct"/> - <click stepKey="addProductsToOrder" selector="{{OrdersGridSection.addProductsToOrder}}"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <!--Select shipping method--> - <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShipping"/> - <!--Fill Card data and submit order--> - <click selector="{{AuthorizenetConfigurationSection.paymentMethod}}" stepKey="clickToSetPaymentMethod"/> - <selectOption selector="{{AuthorizenetConfigurationSection.cardType}}" userInput="Visa" stepKey="SelectCreditCard"/> - <fillField selector="{{AuthorizenetConfigurationSection.cardNumber}}" userInput="4111111111111111" stepKey="fillCardNumber"/> - <selectOption selector="{{AuthorizenetConfigurationSection.month}}" userInput="01 - January" stepKey="SelectMonth"/> - <click selector="{{AuthorizenetConfigurationSection.year}}" stepKey="clickYear"/> - <waitForElementVisible selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="waitForDropDownMenuAppeared"/> - <click selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="selectYear"/> - <fillField selector="{{AuthorizenetConfigurationSection.verificationNumber}}" userInput="123" stepKey="fillVerificationNumber"/> - <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="SubmitOrder"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <!--Get order ID and open order page--> - <see userinput="You created the order." stepKey="verifyOrderCreated"/> - <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId"/> - <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> - <argument name="orderId" value="$getOrderId"/> - </actionGroup> - <click selector="{{AdminDataGridTableSection.rowViewAction('1')}}" stepKey="clickCreatedOrderInGrid"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <!--Verify required data--> - <see userinput="Credit Card Direct Post (Authorize.net)" stepKey="checkPaymentMethod"/> - <see userinput="Credit Card Type: MasterCard" stepKey="checkCardType"/> - <see userinput="Credit Card Number: XXXX1111" stepKey="checkCardCode"/> - <see userinput="AVS Response Code:" stepKey="checkAVSResponseCode"/> - <see userinput="Processor Authentication Code:" stepKey="checkProcessorAuthorizationCode"/> - <see userinput="Processor Response Text:" stepKey="checkProcessorResponseText"/> - <see userinput="CVV2 Response Code:" stepKey="checkCVVResponseCode"/> - <see userinput="The order was placed using USD." stepKey="checkCurrency"/> - </test> -</tests> From 5c0bcfd2160d549c082d7f51df0562ab674a9fe6 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 2 Nov 2018 11:58:47 +0200 Subject: [PATCH 0437/1158] Refactored flow for new authorization check logic --- .../Model/Resolver/CartAddress.php | 49 ++--------------- .../SetShippingMethodsOnCart.php | 52 +++++-------------- 2 files changed, 19 insertions(+), 82 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php index d2b502688adbc..54bd8fa2a5717 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php @@ -8,15 +8,11 @@ namespace Magento\QuoteGraphQl\Model\Resolver; use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; -use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteId; -use Magento\QuoteGraphQl\Model\Authorization\IsCartMutationAllowedForCurrentUser; use Magento\QuoteGraphQl\Model\Resolver\Address\AddressDataProvider; /** @@ -29,11 +25,6 @@ class CartAddress implements ResolverInterface */ private $addressDataProvider; - /** - * @var IsCartMutationAllowedForCurrentUser - */ - private $isCartMutationAllowedForCurrentUser; - /** * @var CartRepositoryInterface */ @@ -50,18 +41,15 @@ class CartAddress implements ResolverInterface * @param MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId * @param CartRepositoryInterface $cartRepository * @param AddressDataProvider $addressDataProvider - * @param IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser */ public function __construct( MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId, CartRepositoryInterface $cartRepository, - AddressDataProvider $addressDataProvider, - IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser + AddressDataProvider $addressDataProvider ) { $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->cartRepository = $cartRepository; $this->addressDataProvider = $addressDataProvider; - $this->isCartMutationAllowedForCurrentUser = $isCartMutationAllowedForCurrentUser; } /** @@ -69,39 +57,12 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { - /* The cart_id is used instead of the model because some parent resolvers do not work - with cart model */ - if (!isset($value['cart_id'])) { - throw new LocalizedException(__('"cart_id" value should be specified')); + if (!isset($value['model'])) { + throw new LocalizedException(__('"model" value should be specified')); } - $maskedCartId = $value['cart_id']; - - try { - $quoteId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); - } catch (NoSuchEntityException $exception) { - throw new GraphQlNoSuchEntityException( - __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $maskedCartId]) - ); - } - - if (false === $this->isCartMutationAllowedForCurrentUser->execute($quoteId)) { - throw new GraphQlAuthorizationException( - __( - 'The current user cannot perform operations on cart "%masked_cart_id"', - ['masked_cart_id' => $maskedCartId] - ) - ); - } - - try { - $quote = $this->cartRepository->get($quoteId); - } catch (NoSuchEntityException $exception) { - throw new GraphQlNoSuchEntityException( - __('Could not find a cart with ID "%quote_id"', ['quote_id' => $quoteId]) - ); - } + $cart = $value['model']; - return $this->addressDataProvider->getCartAddresses($quote); + return $this->addressDataProvider->getCartAddresses($cart); } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php index 7e35f97d9f711..97a7bcea8aa48 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php @@ -12,18 +12,16 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; -use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\Stdlib\ArrayManager; -use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; -use Magento\QuoteGraphQl\Model\Authorization\IsCartMutationAllowedForCurrentUser; use Magento\Quote\Model\Quote\AddressFactory as QuoteAddressFactory; use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; use Magento\Checkout\Model\ShippingInformationFactory; +use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; /** * Class SetShippingMethodsOnCart @@ -47,20 +45,15 @@ class SetShippingMethodsOnCart implements ResolverInterface */ private $quoteAddressResource; - /** - * @var MaskedQuoteIdToQuoteIdInterface - */ - private $maskedQuoteIdToQuoteId; - /** * @var ArrayManager */ private $arrayManager; /** - * @var IsCartMutationAllowedForCurrentUser + * @var GetCartForUser */ - private $isCartMutationAllowedForCurrentUser; + private $getCartForUser; /** * @var ShippingInformationManagementInterface @@ -70,8 +63,7 @@ class SetShippingMethodsOnCart implements ResolverInterface /** * SetShippingMethodsOnCart constructor. * @param ArrayManager $arrayManager - * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId - * @param IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser + * @param GetCartForUser $getCartForUser * @param ShippingInformationManagementInterface $shippingInformationManagement * @param QuoteAddressFactory $quoteAddressFactory * @param QuoteAddressResource $quoteAddressResource @@ -79,18 +71,15 @@ class SetShippingMethodsOnCart implements ResolverInterface */ public function __construct( ArrayManager $arrayManager, - MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser, + GetCartForUser $getCartForUser, ShippingInformationManagementInterface $shippingInformationManagement, QuoteAddressFactory $quoteAddressFactory, QuoteAddressResource $quoteAddressResource, ShippingInformationFactory $shippingInformationFactory ) { $this->arrayManager = $arrayManager; - $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->isCartMutationAllowedForCurrentUser = $isCartMutationAllowedForCurrentUser; + $this->getCartForUser = $getCartForUser; $this->shippingInformationManagement = $shippingInformationManagement; - $this->quoteAddressResource = $quoteAddressResource; $this->quoteAddressFactory = $quoteAddressFactory; $this->shippingInformationFactory = $shippingInformationFactory; @@ -111,34 +100,20 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value throw new GraphQlInputException(__('Required parameter "shipping_methods" is missing')); } - $shippingMethod = reset($shippingMethods); // TODO: provide implementation for multishipping + $shippingMethod = reset($shippingMethods); if (!$shippingMethod['cart_address_id']) { throw new GraphQlInputException(__('Required parameter "cart_address_id" is missing')); } - if (!$shippingMethod['shipping_carrier_code']) { // FIXME: check the E_WARNING here + if (!$shippingMethod['shipping_carrier_code']) { throw new GraphQlInputException(__('Required parameter "shipping_carrier_code" is missing')); } - if (!$shippingMethod['shipping_method_code']) { // FIXME: check the E_WARNING here + if (!$shippingMethod['shipping_method_code']) { throw new GraphQlInputException(__('Required parameter "shipping_method_code" is missing')); } - try { - $cartId = $this->maskedQuoteIdToQuoteId->execute((string) $maskedCartId); - } catch (NoSuchEntityException $exception) { - throw new GraphQlNoSuchEntityException( - __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $maskedCartId]) - ); - } - - if (false === $this->isCartMutationAllowedForCurrentUser->execute($cartId)) { - throw new GraphQlAuthorizationException( - __( - 'The current user cannot perform operations on cart "%masked_cart_id"', - ['masked_cart_id' => $maskedCartId] - ) - ); - } + $userId = $context->getUserId(); + $cart = $this->getCartForUser->execute((string) $maskedCartId, $userId); $quoteAddress = $this->quoteAddressFactory->create(); $this->quoteAddressResource->load($quoteAddress, $shippingMethod['cart_address_id']); @@ -153,7 +128,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $shippingInformation->setShippingMethodCode($shippingMethod['shipping_method_code']); try { - $this->shippingInformationManagement->saveAddressInformation($cartId, $shippingInformation); + $this->shippingInformationManagement->saveAddressInformation($cart->getId(), $shippingInformation); } catch (NoSuchEntityException $exception) { throw new GraphQlNoSuchEntityException(__($exception->getMessage())); } catch (StateException $exception) { @@ -164,7 +139,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value return [ 'cart' => [ - 'cart_id' => $maskedCartId + 'cart_id' => $maskedCartId, + 'model' => $cart ] ]; } From effd4cd58724717aa561f8745a13b32c1d5125f2 Mon Sep 17 00:00:00 2001 From: Bernard van der Esch <b.vanderesch@gmail.com> Date: Fri, 2 Nov 2018 11:29:18 +0100 Subject: [PATCH 0438/1158] missing use statement in layout generator --- lib/internal/Magento/Framework/View/Layout/Generator/Block.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/View/Layout/Generator/Block.php b/lib/internal/Magento/Framework/View/Layout/Generator/Block.php index bc250c54e7946..c69421cda339a 100755 --- a/lib/internal/Magento/Framework/View/Layout/Generator/Block.php +++ b/lib/internal/Magento/Framework/View/Layout/Generator/Block.php @@ -6,6 +6,7 @@ namespace Magento\Framework\View\Layout\Generator; use Magento\Framework\App\State; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\ObjectManager\Config\Reader\Dom; use Magento\Framework\View\Element\Template; use Magento\Framework\View\Layout; From c98c3d5142d73789e8233deb4aa90f172d716c21 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 2 Nov 2018 12:29:44 +0200 Subject: [PATCH 0439/1158] Logic for setting shipping method is moved to a separate class --- .../SetShippingMethodOnCart.php} | 84 ++++------------ .../Resolver/SetShippingMethodsOnCart.php | 99 +++++++++++++++++++ .../Magento/QuoteGraphQl/etc/schema.graphqls | 2 +- 3 files changed, 119 insertions(+), 66 deletions(-) rename app/code/Magento/QuoteGraphQl/Model/{Resolver/ShippingMethod/SetShippingMethodsOnCart.php => Cart/SetShippingMethodOnCart.php} (54%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingMethodsOnCart.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php similarity index 54% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php rename to app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php index 97a7bcea8aa48..7f945dca2fd76 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingMethod/SetShippingMethodsOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php @@ -5,30 +5,26 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\ShippingMethod; +namespace Magento\QuoteGraphQl\Model\Cart; -use Magento\Checkout\Api\ShippingInformationManagementInterface; -use Magento\Checkout\Model\ShippingInformation; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Framework\Stdlib\ArrayManager; +use Magento\Quote\Model\Quote; use Magento\Quote\Model\Quote\AddressFactory as QuoteAddressFactory; use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; use Magento\Checkout\Model\ShippingInformationFactory; -use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; +use Magento\Checkout\Api\ShippingInformationManagementInterface; +use Magento\Checkout\Model\ShippingInformation; /** * Class SetShippingMethodsOnCart * - * Mutation resolver for setting shipping methods for shopping cart + * Set shipping method for a specified shopping cart address */ -class SetShippingMethodsOnCart implements ResolverInterface +class SetShippingMethodOnCart { /** * @var ShippingInformationFactory @@ -45,40 +41,23 @@ class SetShippingMethodsOnCart implements ResolverInterface */ private $quoteAddressResource; - /** - * @var ArrayManager - */ - private $arrayManager; - - /** - * @var GetCartForUser - */ - private $getCartForUser; - /** * @var ShippingInformationManagementInterface */ private $shippingInformationManagement; /** - * SetShippingMethodsOnCart constructor. - * @param ArrayManager $arrayManager - * @param GetCartForUser $getCartForUser * @param ShippingInformationManagementInterface $shippingInformationManagement * @param QuoteAddressFactory $quoteAddressFactory * @param QuoteAddressResource $quoteAddressResource * @param ShippingInformationFactory $shippingInformationFactory */ public function __construct( - ArrayManager $arrayManager, - GetCartForUser $getCartForUser, ShippingInformationManagementInterface $shippingInformationManagement, QuoteAddressFactory $quoteAddressFactory, QuoteAddressResource $quoteAddressResource, ShippingInformationFactory $shippingInformationFactory ) { - $this->arrayManager = $arrayManager; - $this->getCartForUser = $getCartForUser; $this->shippingInformationManagement = $shippingInformationManagement; $this->quoteAddressResource = $quoteAddressResource; $this->quoteAddressFactory = $quoteAddressFactory; @@ -86,37 +65,19 @@ public function __construct( } /** - * @inheritdoc + * Sets shipping method for a specified shopping cart address + * + * @param Quote $cart + * @param int $cartAddressId + * @param string $carrierCode + * @param string $methodCode + * @throws GraphQlInputException + * @throws GraphQlNoSuchEntityException */ - public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + public function execute(Quote $cart, int $cartAddressId, string $carrierCode, string $methodCode): void { - $shippingMethods = $this->arrayManager->get('input/shipping_methods', $args); - $maskedCartId = $this->arrayManager->get('input/cart_id', $args); - - if (!$maskedCartId) { - throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); - } - if (!$shippingMethods) { - throw new GraphQlInputException(__('Required parameter "shipping_methods" is missing')); - } - - $shippingMethod = reset($shippingMethods); - - if (!$shippingMethod['cart_address_id']) { - throw new GraphQlInputException(__('Required parameter "cart_address_id" is missing')); - } - if (!$shippingMethod['shipping_carrier_code']) { - throw new GraphQlInputException(__('Required parameter "shipping_carrier_code" is missing')); - } - if (!$shippingMethod['shipping_method_code']) { - throw new GraphQlInputException(__('Required parameter "shipping_method_code" is missing')); - } - - $userId = $context->getUserId(); - $cart = $this->getCartForUser->execute((string) $maskedCartId, $userId); - $quoteAddress = $this->quoteAddressFactory->create(); - $this->quoteAddressResource->load($quoteAddress, $shippingMethod['cart_address_id']); + $this->quoteAddressResource->load($quoteAddress, $cartAddressId); /** @var ShippingInformation $shippingInformation */ $shippingInformation = $this->shippingInformationFactory->create(); @@ -124,8 +85,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value /* If the address is not a shipping address (but billing) the system will find the proper shipping address for the selected cart and set the information there (actual for single shipping address) */ $shippingInformation->setShippingAddress($quoteAddress); - $shippingInformation->setShippingCarrierCode($shippingMethod['shipping_carrier_code']); - $shippingInformation->setShippingMethodCode($shippingMethod['shipping_method_code']); + $shippingInformation->setShippingCarrierCode($carrierCode); + $shippingInformation->setShippingMethodCode($methodCode); try { $this->shippingInformationManagement->saveAddressInformation($cart->getId(), $shippingInformation); @@ -136,12 +97,5 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value } catch (InputException $exception) { throw new GraphQlInputException(__($exception->getMessage())); } - - return [ - 'cart' => [ - 'cart_id' => $maskedCartId, - 'model' => $cart - ] - ]; } -} +} \ No newline at end of file diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingMethodsOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingMethodsOnCart.php new file mode 100644 index 0000000000000..920829f5d67b1 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingMethodsOnCart.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; +use Magento\QuoteGraphQl\Model\Cart\SetShippingMethodOnCart; + +/** + * Class SetShippingMethodsOnCart + * + * Mutation resolver for setting shipping methods for shopping cart + */ +class SetShippingMethodsOnCart implements ResolverInterface +{ + /** + * @var SetShippingMethodOnCart + */ + private $setShippingMethodOnCart; + + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * @var GetCartForUser + */ + private $getCartForUser; + + /** + * @param ArrayManager $arrayManager + * @param GetCartForUser $getCartForUser + * @param SetShippingMethodOnCart $setShippingMethodOnCart + */ + public function __construct( + ArrayManager $arrayManager, + GetCartForUser $getCartForUser, + SetShippingMethodOnCart $setShippingMethodOnCart + ) { + $this->arrayManager = $arrayManager; + $this->getCartForUser = $getCartForUser; + $this->setShippingMethodOnCart = $setShippingMethodOnCart; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $shippingMethods = $this->arrayManager->get('input/shipping_methods', $args); + $maskedCartId = $this->arrayManager->get('input/cart_id', $args); + + if (!$maskedCartId) { + throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); + } + if (!$shippingMethods) { + throw new GraphQlInputException(__('Required parameter "shipping_methods" is missing')); + } + + $shippingMethod = reset($shippingMethods); // This point can be extended for multishipping + + if (!$shippingMethod['cart_address_id']) { + throw new GraphQlInputException(__('Required parameter "cart_address_id" is missing')); + } + if (!$shippingMethod['shipping_carrier_code']) { + throw new GraphQlInputException(__('Required parameter "shipping_carrier_code" is missing')); + } + if (!$shippingMethod['shipping_method_code']) { + throw new GraphQlInputException(__('Required parameter "shipping_method_code" is missing')); + } + + $userId = $context->getUserId(); + $cart = $this->getCartForUser->execute((string) $maskedCartId, $userId); + + $this->setShippingMethodOnCart->execute( + $cart, + $shippingMethod['cart_address_id'], + $shippingMethod['shipping_carrier_code'], + $shippingMethod['shipping_method_code'] + ); + + return [ + 'cart' => [ + 'cart_id' => $maskedCartId, + 'model' => $cart + ] + ]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index cbc56bfaea66f..ce982952f1aee 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -11,7 +11,7 @@ type Mutation { removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveCouponFromCart") setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput - setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ShippingMethod\\SetShippingMethodsOnCart") + setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingMethodsOnCart") addSimpleProductsToCart(input: AddSimpleProductsToCartInput): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") } From c8dbdf4a1b94c5d3f6b9f3211f270c0168d74396 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Fri, 2 Nov 2018 12:37:27 +0200 Subject: [PATCH 0440/1158] graphQl: fixed multi shipping model --- .../MultiShipping/ShippingItemsMapper.php | 2 +- .../Magento/QuoteGraphQl/etc/graphql/di.xml | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/QuoteGraphQl/etc/graphql/di.xml diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php index c9cefc421a544..ad5207814db7c 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php @@ -14,7 +14,7 @@ class ShippingItemsMapper { /** - * Converts shipping address input array into shipping items information array + * Converts shipping address input array into shipping items information array * Array structure: * array( * $cartItemId => array( diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml new file mode 100644 index 0000000000000..43941c9740048 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <virtualType name="multishippingPaymentSpecification" type="Magento\Payment\Model\Method\Specification\Composite"> + <arguments> + <argument name="specifications" xsi:type="array"> + <item name="enabled" xsi:type="string">Magento\Multishipping\Model\Payment\Method\Specification\Enabled</item> + </argument> + </arguments> + </virtualType> + <type name="Magento\Multishipping\Block\Checkout\Billing"> + <arguments> + <argument name="paymentSpecification" xsi:type="object">multishippingPaymentSpecification</argument> + </arguments> + </type> + <type name="Magento\Multishipping\Model\Checkout\Type\Multishipping"> + <arguments> + <argument name="paymentSpecification" xsi:type="object">multishippingPaymentSpecification</argument> + </arguments> + </type> +</config> From 166259009ae6e741ca90c98472c763d488a6839d Mon Sep 17 00:00:00 2001 From: Bernard van der Esch <b.vanderesch@gmail.com> Date: Fri, 2 Nov 2018 11:43:29 +0100 Subject: [PATCH 0441/1158] import class to the use statement --- lib/internal/Magento/Framework/View/Layout/Generator/Block.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/View/Layout/Generator/Block.php b/lib/internal/Magento/Framework/View/Layout/Generator/Block.php index c69421cda339a..f0e62fce2a7ce 100755 --- a/lib/internal/Magento/Framework/View/Layout/Generator/Block.php +++ b/lib/internal/Magento/Framework/View/Layout/Generator/Block.php @@ -273,7 +273,7 @@ protected function getBlockInstance($block, array $arguments = []) } } if (!$block instanceof \Magento\Framework\View\Element\AbstractBlock) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( new \Magento\Framework\Phrase( 'Invalid block type: %1', [is_object($block) ? get_class($block) : (string) $block] From 5224958b90b3013b5c213e1b76e2522a3ca2e45e Mon Sep 17 00:00:00 2001 From: Oleksii Gorbulin <a.gorbulin@ism-ukraine.com> Date: Fri, 2 Nov 2018 13:20:59 +0200 Subject: [PATCH 0442/1158] Add-validation-new-from-date-less-than-new-to-date-in-SCV-product-import add validation for fields new_from_date and new_to_date to make sure field new_from_date < new_to_date to prevent future errors during saving updated product --- .../Model/Import/Product.php | 29 +++++++++++++++++-- .../Import/Product/RowValidatorInterface.php | 2 ++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 6f8b2248d8d89..0595617fcf382 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -132,6 +132,16 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity */ const COL_NAME = 'name'; + /** + * Column new_from_date. + */ + const COL_NEW_FROM_DATE = 'new_from_date'; + + /** + * Column new_to_date. + */ + const COL_NEW_TO_DATE = 'new_to_date'; + /** * Column product website. */ @@ -298,6 +308,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity ValidatorInterface::ERROR_INVALID_WEIGHT => 'Product weight is invalid', ValidatorInterface::ERROR_DUPLICATE_URL_KEY => 'Url key: \'%s\' was already generated for an item with the SKU: \'%s\'. You need to specify the unique URL key manually', ValidatorInterface::ERROR_DUPLICATE_MULTISELECT_VALUES => "Value for multiselect attribute %s contains duplicated values", + ValidatorInterface::ERROR_NEW_TO_DATE => 'Make sure new_to_date is later than or the same as new_from_date', ]; //@codingStandardsIgnoreEnd @@ -319,8 +330,8 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity Product::COL_TYPE => 'product_type', Product::COL_PRODUCT_WEBSITES => 'product_websites', 'status' => 'product_online', - 'news_from_date' => 'new_from_date', - 'news_to_date' => 'new_to_date', + 'news_from_date' => self::COL_NEW_FROM_DATE, + 'news_to_date' => self::COL_NEW_TO_DATE, 'options_container' => 'display_product_options_in', 'minimal_price' => 'map_price', 'msrp' => 'msrp_price', @@ -2546,6 +2557,20 @@ public function validateRow(array $rowData, $rowNum) } } } + + if (!empty($rowData[self::COL_NEW_FROM_DATE]) && !empty($rowData[self::COL_NEW_TO_DATE]) + ) { + $newFromTimestamp = strtotime($this->dateTime->formatDate($rowData[self::COL_NEW_FROM_DATE], false)); + $newToTimestamp = strtotime($this->dateTime->formatDate($rowData[self::COL_NEW_TO_DATE], false)); + if ($newFromTimestamp > $newToTimestamp) { + $this->addRowError( + ValidatorInterface::ERROR_NEW_TO_DATE, + $rowNum, + $rowData[self::COL_NEW_TO_DATE] + ); + } + } + return !$this->getErrorAggregator()->isRowInvalid($rowNum); } diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php index f41596ad185a6..cbdc5f5beaaf9 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php @@ -87,6 +87,8 @@ interface RowValidatorInterface extends \Magento\Framework\Validator\ValidatorIn const ERROR_DUPLICATE_MULTISELECT_VALUES = 'duplicatedMultiselectValues'; + const ERROR_NEW_TO_DATE = 'invalidNewToDateValue'; + /** * Value that means all entities (e.g. websites, groups etc.) */ From 388fb45eb6ff24b3fe9fc1452bf75db5507ae87c Mon Sep 17 00:00:00 2001 From: Vladyslav Podorozhnyi <v.podorozhnyi@ism-ukraine.com> Date: Fri, 2 Nov 2018 13:42:44 +0200 Subject: [PATCH 0443/1158] magento/magento2#17833: Child theme does not inherit translations from parent theme --- lib/internal/Magento/Framework/Translate.php | 76 ++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/lib/internal/Magento/Framework/Translate.php b/lib/internal/Magento/Framework/Translate.php index ffa8e25031064..3d5213cb2a40e 100644 --- a/lib/internal/Magento/Framework/Translate.php +++ b/lib/internal/Magento/Framework/Translate.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Framework; @@ -339,16 +340,21 @@ protected function _addData($data) } /** - * Load current theme translation + * Load current theme translation according to fallback * * @return $this */ protected function _loadThemeTranslation() { - $file = $this->_getThemeTranslationFile($this->getLocale()); - if ($file) { - $this->_addData($this->_getFileData($file)); + $themeFiles = $this->getThemeTranslationFilesList($this->getLocale()); + + /** @var string $file */ + foreach ($themeFiles as $file) { + if ($file) { + $this->_addData($this->_getFileData($file)); + } } + return $this; } @@ -389,11 +395,73 @@ protected function _getModuleTranslationFile($moduleName, $locale) return $file; } + /** + * Get theme translation locale file name + * + * @param string $locale + * @param array $config + * @return string + */ + private function getThemeTranslationFileName(string $locale, array $config): string + { + return $this->_viewFileSystem->getLocaleFileName( + 'i18n' . '/' . $locale . '.csv', + $config + ); + } + + /** + * Get parent themes for the current theme in fallback order + * + * @return array + */ + private function getParentThemesList(): array + { + $themes = []; + + $parentTheme = $this->_viewDesign->getDesignTheme()->getParentTheme(); + while($parentTheme) { + $themes[] = $parentTheme; + $parentTheme = $parentTheme->getParentTheme(); + } + $themes = array_reverse($themes); + + return $themes; + } + + /** + * Retrieve translation files for themes according to fallback + * + * @param string $locale + * + * @return array + */ + private function getThemeTranslationFilesList($locale): array + { + $translationFiles = []; + + /** @var \Magento\Framework\View\Design\ThemeInterface $theme */ + foreach ($this->getParentThemesList() as $theme) { + $config = $this->_config; + $config['theme'] = $theme->getCode(); + $translationFiles[] = $this->getThemeTranslationFileName($locale, $config); + } + + $translationFiles[] = $this->getThemeTranslationFileName($locale, $this->_config); + + return $translationFiles; + } + + /** * Retrieve translation file for theme * * @param string $locale * @return string + * + * @deprecated + * + * @see \Magento\Framework\Translate::getThemeTranslationFilesList */ protected function _getThemeTranslationFile($locale) { From 63cbe3b36a46442a53fa13db27e039aed318ebc9 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Fri, 2 Nov 2018 13:48:11 +0200 Subject: [PATCH 0444/1158] MAGETWO-91639: Tax is added despite customer group changes - Fixing integrity test --- app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php index 303c95b965b98..03b19c6e661a9 100644 --- a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php +++ b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php @@ -10,6 +10,7 @@ use Magento\Quote\Api\CartRepositoryInterface; use Magento\Customer\Model\ResourceModel\Customer as CustomerResource; use Magento\Customer\Model\Customer; +use Magento\Framework\Model\AbstractModel; /** * Recollect quote totals after change customer group @@ -35,13 +36,14 @@ public function __construct( * * @param CustomerResource $subject * @param CustomerResource $result - * @param Customer $customer + * @param AbstractModel $customer * @return CustomerResource * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function afterSave(CustomerResource $subject, CustomerResource $result, Customer $customer) + public function afterSave(CustomerResource $subject, CustomerResource $result, AbstractModel $customer) { + /** @var Customer $customer */ if ($customer->getOrigData('group_id') !== null && $customer->getOrigData('group_id') != $customer->getGroupId() ) { From 6a35e24869be3384e9f7d86bf6faed132d5b2bf6 Mon Sep 17 00:00:00 2001 From: Vladyslav Podorozhnyi <v.podorozhnyi@ism-ukraine.com> Date: Fri, 2 Nov 2018 14:16:30 +0200 Subject: [PATCH 0445/1158] =?UTF-8?q?magento/magento2#17833:=C2=A0=20Child?= =?UTF-8?q?=20theme=20does=20not=20inherit=20translations=20from=20parent?= =?UTF-8?q?=20theme=20-=20fix=20code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/internal/Magento/Framework/Translate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Translate.php b/lib/internal/Magento/Framework/Translate.php index 3d5213cb2a40e..7994c22c14806 100644 --- a/lib/internal/Magento/Framework/Translate.php +++ b/lib/internal/Magento/Framework/Translate.php @@ -420,7 +420,7 @@ private function getParentThemesList(): array $themes = []; $parentTheme = $this->_viewDesign->getDesignTheme()->getParentTheme(); - while($parentTheme) { + while ($parentTheme) { $themes[] = $parentTheme; $parentTheme = $parentTheme->getParentTheme(); } From 51e240203aad14b5a0dcce42caf9041c92fc138d Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Fri, 2 Nov 2018 15:29:33 +0300 Subject: [PATCH 0446/1158] MAGETWO-91684: Issue with Newsletter subscriptions - Ensure that customer id is presented. --- .../Model/ResourceModel/Subscriber.php | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php index 5bd89c2798ce3..f9e9d57bf4b40 100644 --- a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php @@ -132,28 +132,34 @@ public function loadByCustomerData(\Magento\Customer\Api\Data\CustomerInterface { $storeIds = $this->storeManager->getWebsite($customer->getWebsiteId())->getStoreIds(); - $select = $this->connection - ->select() - ->from($this->getMainTable()) - ->where('customer_id = ?', $customer->getId()) - ->where('store_id IN (?)', $storeIds); - - $result = $this->connection->fetchRow($select); - - if ($result) { - return $result; + if ($customer->getId()) { + $select = $this->connection + ->select() + ->from($this->getMainTable()) + ->where('customer_id = ?', $customer->getId()) + ->where('store_id IN (?)', $storeIds) + ->limit(1); + + $result = $this->connection->fetchRow($select); + + if ($result) { + return $result; + } } - $select = $this->connection - ->select() - ->from($this->getMainTable()) - ->where('subscriber_email = ?', $customer->getEmail()) - ->where('store_id IN (?)', $storeIds); + if ($customer->getEmail()) { + $select = $this->connection + ->select() + ->from($this->getMainTable()) + ->where('subscriber_email = ?', $customer->getEmail()) + ->where('store_id IN (?)', $storeIds) + ->limit(1); - $result = $this->connection->fetchRow($select); + $result = $this->connection->fetchRow($select); - if ($result) { - return $result; + if ($result) { + return $result; + } } return []; From 16731a0812d9a74fb55d4acc8e68af3716e1c728 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Fri, 2 Nov 2018 15:00:55 +0200 Subject: [PATCH 0447/1158] MAGETWO-96007: Customer address issue when creating or updating via API --- .../ResourceModel/CustomerRepositoryTest.php | 161 +++++++++++++----- 1 file changed, 114 insertions(+), 47 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php index 1af093bea06cc..15afc87405ffd 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php @@ -8,8 +8,24 @@ use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterfaceFactory; +use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Customer\Api\Data\RegionInterfaceFactory; +use Magento\Framework\Api\ExtensibleDataObjectConverter; +use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\Encryption\EncryptorInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\CustomerRegistry; use Magento\Framework\Api\SortOrder; +use Magento\Framework\Config\CacheInterface; +use Magento\Framework\ObjectManagerInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SortOrderBuilder; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Customer\Model\Customer; /** * Checks Customer insert, update, search with repository @@ -24,60 +40,65 @@ class CustomerRepositoryTest extends \PHPUnit\Framework\TestCase /** @var CustomerRepositoryInterface */ private $customerRepository; - /** @var \Magento\Framework\ObjectManagerInterface */ + /** @var ObjectManagerInterface */ private $objectManager; - /** @var \Magento\Customer\Api\Data\CustomerInterfaceFactory */ + /** @var CustomerInterfaceFactory */ private $customerFactory; - /** @var \Magento\Customer\Api\Data\AddressInterfaceFactory */ + /** @var AddressInterfaceFactory */ private $addressFactory; - /** @var \Magento\Customer\Api\Data\RegionInterfaceFactory */ + /** @var RegionInterfaceFactory */ private $regionFactory; - /** @var \Magento\Framework\Api\ExtensibleDataObjectConverter */ + /** @var ExtensibleDataObjectConverter */ private $converter; - /** @var \Magento\Framework\Api\DataObjectHelper */ + /** @var DataObjectHelper */ protected $dataObjectHelper; - /** @var \Magento\Framework\Encryption\EncryptorInterface */ + /** @var EncryptorInterface */ protected $encryptor; - /** @var \Magento\Customer\Model\CustomerRegistry */ + /** @var CustomerRegistry */ protected $customerRegistry; + /** + * @inheritdoc + */ protected function setUp() { $this->objectManager = Bootstrap::getObjectManager(); - $this->customerRepository = - $this->objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); - $this->customerFactory = - $this->objectManager->create(\Magento\Customer\Api\Data\CustomerInterfaceFactory::class); - $this->addressFactory = $this->objectManager->create(\Magento\Customer\Api\Data\AddressInterfaceFactory::class); - $this->regionFactory = $this->objectManager->create(\Magento\Customer\Api\Data\RegionInterfaceFactory::class); - $this->accountManagement = - $this->objectManager->create(\Magento\Customer\Api\AccountManagementInterface::class); - $this->converter = $this->objectManager->create(\Magento\Framework\Api\ExtensibleDataObjectConverter::class); - $this->dataObjectHelper = $this->objectManager->create(\Magento\Framework\Api\DataObjectHelper::class); - $this->encryptor = $this->objectManager->create(\Magento\Framework\Encryption\EncryptorInterface::class); - $this->customerRegistry = $this->objectManager->create(\Magento\Customer\Model\CustomerRegistry::class); - - /** @var \Magento\Framework\Config\CacheInterface $cache */ - $cache = $this->objectManager->create(\Magento\Framework\Config\CacheInterface::class); + $this->customerRepository = $this->objectManager->create(CustomerRepositoryInterface::class); + $this->customerFactory = $this->objectManager->create(CustomerInterfaceFactory::class); + $this->addressFactory = $this->objectManager->create(AddressInterfaceFactory::class); + $this->regionFactory = $this->objectManager->create(RegionInterfaceFactory::class); + $this->accountManagement = $this->objectManager->create(AccountManagementInterface::class); + $this->converter = $this->objectManager->create(ExtensibleDataObjectConverter::class); + $this->dataObjectHelper = $this->objectManager->create(DataObjectHelper::class); + $this->encryptor = $this->objectManager->create(EncryptorInterface::class); + $this->customerRegistry = $this->objectManager->create(CustomerRegistry::class); + + /** @var CacheInterface $cache */ + $cache = $this->objectManager->create(CacheInterface::class); $cache->remove('extension_attributes_config'); } + /** + * @inheritdoc + */ protected function tearDown() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager = Bootstrap::getObjectManager(); /** @var \Magento\Customer\Model\CustomerRegistry $customerRegistry */ - $customerRegistry = $objectManager->get(\Magento\Customer\Model\CustomerRegistry::class); + $customerRegistry = $objectManager->get(CustomerRegistry::class); $customerRegistry->remove(1); } /** + * Check if first name update was successful + * * @magentoDbIsolation enabled */ public function testCreateCustomerNewThenUpdateFirstName() @@ -99,7 +120,7 @@ public function testCreateCustomerNewThenUpdateFirstName() $newCustomerFirstname = 'New First Name'; $updatedCustomer = $this->customerFactory->create(); $this->dataObjectHelper->mergeDataObjects( - \Magento\Customer\Api\Data\CustomerInterface::class, + CustomerInterface::class, $updatedCustomer, $customer ); @@ -112,6 +133,8 @@ public function testCreateCustomerNewThenUpdateFirstName() } /** + * Test create new customer + * * @magentoDbIsolation enabled */ public function testCreateNewCustomer() @@ -139,6 +162,8 @@ public function testCreateNewCustomer() } /** + * Test update customer + * * @dataProvider updateCustomerDataProvider * @magentoAppArea frontend * @magentoDataFixture Magento/Customer/_files/customer.php @@ -168,7 +193,7 @@ public function testUpdateCustomer($defaultBilling, $defaultShipping) $this->dataObjectHelper->populateWithArray( $customerDetails, $customerData, - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); $this->customerRepository->save($customerDetails, $newPasswordHash); $customerAfter = $this->customerRepository->getById($existingCustomerId); @@ -187,12 +212,12 @@ public function testUpdateCustomer($defaultBilling, $defaultShipping) $attributesBefore = $this->converter->toFlatArray( $customerBefore, [], - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); $attributesAfter = $this->converter->toFlatArray( $customerAfter, [], - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); // ignore 'updated_at' unset($attributesBefore['updated_at']); @@ -215,6 +240,8 @@ public function testUpdateCustomer($defaultBilling, $defaultShipping) } /** + * Test update customer address + * * @magentoAppArea frontend * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php @@ -233,14 +260,14 @@ public function testUpdateCustomerAddress() $this->dataObjectHelper->populateWithArray( $newAddressDataObject, $newAddress, - \Magento\Customer\Api\Data\AddressInterface::class + AddressInterface::class ); $newAddressDataObject->setRegion($addresses[0]->getRegion()); $newCustomerEntity = $this->customerFactory->create(); $this->dataObjectHelper->populateWithArray( $newCustomerEntity, $customerDetails, - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); $newCustomerEntity->setId($customerId) ->setAddresses([$newAddressDataObject, $addresses[1]]); @@ -256,6 +283,8 @@ public function testUpdateCustomerAddress() } /** + * Test preserve all addresses after customer update + * * @magentoAppArea frontend * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php @@ -265,22 +294,37 @@ public function testUpdateCustomerPreserveAllAddresses() $customerId = 1; $customer = $this->customerRepository->getById($customerId); $customerDetails = $customer->__toArray(); + $defaultBilling = $customerDetails['default_billing']; + $defaultShipping = $customerDetails['default_shipping']; $newCustomerEntity = $this->customerFactory->create(); $this->dataObjectHelper->populateWithArray( $newCustomerEntity, $customerDetails, - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); $newCustomerEntity->setId($customer->getId()) ->setAddresses(null); $this->customerRepository->save($newCustomerEntity); $newCustomerDetails = $this->customerRepository->getById($customerId); + $newCustomerArray = $newCustomerDetails->__toArray(); //Verify that old addresses are still present $this->assertEquals(2, count($newCustomerDetails->getAddresses())); + $this->assertEquals( + $defaultBilling, + $newCustomerArray['default_billing'], + "Default billing invalid value" + ); + $this->assertEquals( + $defaultShipping, + $newCustomerArray['default_shipping'], + "Default shipping invalid value" + ); } /** + * Test update delete all addresses with empty arrays + * * @magentoAppArea frontend * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php @@ -294,18 +338,31 @@ public function testUpdateCustomerDeleteAllAddressesWithEmptyArray() $this->dataObjectHelper->populateWithArray( $newCustomerEntity, $customerDetails, - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); $newCustomerEntity->setId($customer->getId()) ->setAddresses([]); $this->customerRepository->save($newCustomerEntity); $newCustomerDetails = $this->customerRepository->getById($customerId); + $newCustomerArray = $newCustomerDetails->__toArray(); //Verify that old addresses are removed $this->assertEquals(0, count($newCustomerDetails->getAddresses())); + $this->assertEquals( + $newCustomerArray['default_billing'], + null, + "Default billing invalid value" + ); + $this->assertEquals( + $newCustomerArray['default_shipping'], + null, + "Default shipping invalid value" + ); } /** + * Test search customers + * * @param \Magento\Framework\Api\Filter[] $filters * @param \Magento\Framework\Api\Filter[] $filterGroup * @param array $expectedResult array of expected results indexed by ID @@ -317,9 +374,8 @@ public function testUpdateCustomerDeleteAllAddressesWithEmptyArray() */ public function testSearchCustomers($filters, $filterGroup, $expectedResult) { - /** @var \Magento\Framework\Api\SearchCriteriaBuilder $searchBuilder */ - $searchBuilder = Bootstrap::getObjectManager() - ->create(\Magento\Framework\Api\SearchCriteriaBuilder::class); + /** @var SearchCriteriaBuilder $searchBuilder */ + $searchBuilder = Bootstrap::getObjectManager()->create(SearchCriteriaBuilder::class); foreach ($filters as $filter) { $searchBuilder->addFilters([$filter]); } @@ -346,19 +402,19 @@ public function testSearchCustomers($filters, $filterGroup, $expectedResult) */ public function testSearchCustomersOrder() { - /** @var \Magento\Framework\Api\SearchCriteriaBuilder $searchBuilder */ + /** @var SearchCriteriaBuilder $searchBuilder */ $objectManager = Bootstrap::getObjectManager(); - $searchBuilder = $objectManager->create(\Magento\Framework\Api\SearchCriteriaBuilder::class); + $searchBuilder = $objectManager->create(SearchCriteriaBuilder::class); // Filter for 'firstname' like 'First' - $filterBuilder = $objectManager->create(\Magento\Framework\Api\FilterBuilder::class); + $filterBuilder = $objectManager->create(FilterBuilder::class); $firstnameFilter = $filterBuilder->setField('firstname') ->setConditionType('like') ->setValue('First%') ->create(); $searchBuilder->addFilters([$firstnameFilter]); // Search ascending order - $sortOrderBuilder = $objectManager->create(\Magento\Framework\Api\SortOrderBuilder::class); + $sortOrderBuilder = $objectManager->create(SortOrderBuilder::class); $sortOrder = $sortOrderBuilder ->setField('lastname') ->setDirection(SortOrder::SORT_ASC) @@ -383,6 +439,8 @@ public function testSearchCustomersOrder() } /** + * Test delete + * * @magentoAppArea adminhtml * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoAppIsolation enabled @@ -393,12 +451,14 @@ public function testDelete() $customer = $this->customerRepository->get($fixtureCustomerEmail); $this->customerRepository->delete($customer); /** Ensure that customer was deleted */ - $this->expectException(\Magento\Framework\Exception\NoSuchEntityException::class); + $this->expectException(NoSuchEntityException::class); $this->expectExceptionMessage('No such entity with email = customer@example.com, websiteId = 1'); $this->customerRepository->get($fixtureCustomerEmail); } /** + * Test delete by id + * * @magentoAppArea adminhtml * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoAppIsolation enabled @@ -409,7 +469,7 @@ public function testDeleteById() $fixtureCustomerId = 1; $this->customerRepository->deleteById($fixtureCustomerId); /** Ensure that customer was deleted */ - $this->expectException(\Magento\Framework\Exception\NoSuchEntityException::class); + $this->expectException(NoSuchEntityException::class); $this->expectExceptionMessage('No such entity with email = customer@example.com, websiteId = 1'); $this->customerRepository->get($fixtureCustomerEmail); } @@ -433,9 +493,14 @@ public function updateCustomerDataProvider() ]; } + /** + * Search customer data provider + * + * @return array + */ public function searchCustomersDataProvider() { - $builder = Bootstrap::getObjectManager()->create(\Magento\Framework\Api\FilterBuilder::class); + $builder = Bootstrap::getObjectManager()->create(FilterBuilder::class); return [ 'Customer with specific email' => [ [$builder->setField('email')->setValue('customer@search.example.com')->create()], @@ -485,9 +550,9 @@ protected function expectedDefaultShippingsInCustomerModelAttributes( $defaultShipping ) { /** - * @var \Magento\Customer\Model\Customer $customer + * @var Customer $customer */ - $customer = $this->objectManager->create(\Magento\Customer\Model\Customer::class); + $customer = $this->objectManager->create(Customer::class); /** @var \Magento\Customer\Model\Customer $customer */ $customer->load($customerId); $this->assertEquals( @@ -503,6 +568,8 @@ protected function expectedDefaultShippingsInCustomerModelAttributes( } /** + * Test update default shipping and default billing address + * * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDbIsolation enabled */ @@ -530,13 +597,13 @@ public function testUpdateDefaultShippingAndDefaultBillingTest() $this->assertEquals( $savedCustomer->getDefaultBilling(), $oldDefaultBilling, - 'Default billing shoud not be overridden' + 'Default billing should not be overridden' ); $this->assertEquals( $savedCustomer->getDefaultShipping(), $oldDefaultShipping, - 'Default shipping shoud not be overridden' + 'Default shipping should not be overridden' ); } } From c720d972108e6991f127f6f71e63485290dabe61 Mon Sep 17 00:00:00 2001 From: Vasilii Burlacu <v.burlacu@atwix.com> Date: Fri, 2 Nov 2018 15:05:08 +0200 Subject: [PATCH 0448/1158] magento/magento2:#18979 - API: Bundle Product Option Repository Delete method removes incorrect option --- app/code/Magento/Bundle/Model/OptionRepository.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Bundle/Model/OptionRepository.php b/app/code/Magento/Bundle/Model/OptionRepository.php index 59e658b08df28..a4d579a44174a 100644 --- a/app/code/Magento/Bundle/Model/OptionRepository.php +++ b/app/code/Magento/Bundle/Model/OptionRepository.php @@ -160,10 +160,9 @@ public function delete(\Magento\Bundle\Api\Data\OptionInterface $option) */ public function deleteById($sku, $optionId) { - $product = $this->getProduct($sku); - $optionCollection = $this->type->getOptionsCollection($product); - $optionCollection->setIdFilter($optionId); - $hasBeenDeleted = $this->delete($optionCollection->getFirstItem()); + /** @var \Magento\Bundle\Api\Data\OptionInterface $option */ + $option = $this->get($sku, $optionId); + $hasBeenDeleted = $this->delete($option); return $hasBeenDeleted; } From 21f52259c1f435a0fcb31ceb6f8a664fc2b7bf6c Mon Sep 17 00:00:00 2001 From: Vladyslav Podorozhnyi <v.podorozhnyi@ism-ukraine.com> Date: Fri, 2 Nov 2018 15:14:28 +0200 Subject: [PATCH 0449/1158] =?UTF-8?q?magento/magento2#17833:=C2=A0=20Child?= =?UTF-8?q?=20theme=20does=20not=20inherit=20translations=20from=20parent?= =?UTF-8?q?=20theme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/internal/Magento/Framework/Translate.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/Translate.php b/lib/internal/Magento/Framework/Translate.php index 7994c22c14806..98ba6c0d718c3 100644 --- a/lib/internal/Magento/Framework/Translate.php +++ b/lib/internal/Magento/Framework/Translate.php @@ -400,14 +400,16 @@ protected function _getModuleTranslationFile($moduleName, $locale) * * @param string $locale * @param array $config - * @return string + * @return string|null */ - private function getThemeTranslationFileName(string $locale, array $config): string + private function getThemeTranslationFileName(string $locale, array $config): ?string { - return $this->_viewFileSystem->getLocaleFileName( + $fileName = $this->_viewFileSystem->getLocaleFileName( 'i18n' . '/' . $locale . '.csv', $config ); + + return $fileName ? $fileName : null; } /** From 57e59d8044cca1d85873ecde5d6a00660f4ffb31 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Fri, 2 Nov 2018 15:20:27 +0200 Subject: [PATCH 0450/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Default addresses changes --- .../Model/Customer/DataProviderWithDefaultAddresses.php | 4 ++-- .../Magento/Customer/Model/ResourceModel/Address/Relation.php | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index eafa5907efac9..30edafe3d504c 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -24,7 +24,7 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract /** * @var array */ - private $loadedData; + private $loadedData = []; /** * @var SessionManagerInterface @@ -114,7 +114,7 @@ public function __construct( */ public function getData(): array { - if (null !== $this->loadedData) { + if (!empty($this->loadedData)) { return $this->loadedData; } $items = $this->collection->getItems(); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index a82a814d40772..ae342a1b10dd8 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -73,6 +73,7 @@ private function getDefaultBillingChangedAddress( if ($object->getIsDefaultBilling()) { $changedAddresses['default_billing'] = $object->getId(); } elseif ($customer->getDefaultBillingAddress() + && $object->getIsDefaultBilling() === false && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() ) { $changedAddresses['default_billing'] = null; @@ -97,6 +98,7 @@ private function getDefaultShippingChangedAddress( if ($object->getIsDefaultShipping()) { $changedAddresses['default_shipping'] = $object->getId(); } elseif ($customer->getDefaultShippingAddress() + && $object->getIsDefaultShipping() === false && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() ) { $changedAddresses['default_shipping'] = null; From 936a22328f429b7e0dd631b6b20831ea91695cb6 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 2 Nov 2018 15:23:16 +0200 Subject: [PATCH 0451/1158] Added setting shipping method on cart test coverage concept --- .../Quote/SetShippingMethodOnCartTest.php | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php new file mode 100644 index 0000000000000..64c7cbf9fd42e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php @@ -0,0 +1,120 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Quote; + +use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface; +use Magento\Quote\Model\ResourceModel\Quote as QuoteResource; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test for setting shipping methods on cart + */ +class SetShippingMethodOnCartTest extends GraphQlAbstract +{ + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; + + /** + * @var QuoteResource + */ + private $quoteResource; + + /** + * @var Quote + */ + private $quote; + + /** + * @var QuoteIdToMaskedQuoteIdInterface + */ + private $quoteIdToMaskedId; + + protected function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->quoteResource = $objectManager->create(QuoteResource::class); + $this->quote = $objectManager->create(Quote::class); + $this->quoteIdToMaskedId = $objectManager->create(QuoteIdToMaskedQuoteIdInterface::class); + $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetShippingOnCart() + { + $this->quoteResource->load( + $this->quote, + 'test_order_1', + 'reserved_order_id' + ); + + $shippingAddress = $this->quote->getShippingAddress(); + $shippingAddressId = $shippingAddress->getId(); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + $query = <<<QUERY +mutation { + setShippingMethodsOnCart(input: + { + cart_id: "$maskedQuoteId", + shipping_methods: [ + { + shipping_method_code: "flatrate" + shipping_carrier_code: "flatrate" + cart_address_id: $shippingAddressId + } + ]}) { + + cart { + cart_id, + addresses { + firstname + lastname + company + address_type + city + street + region { + code + label + } + postcode + country { + code + label + } + + selected_shipping_method { + code + label + } + } + } + } +} + +QUERY; + + $customerToken = $this->customerTokenService->createCustomerAccessToken('customer@example.com', 'password'); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + $response = $this->graphQlQuery($query, [], '', $headerMap); + + self::assertArrayHasKey('setShippingMethodsOnCart', $response); + self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']); + self::assertEquals($maskedQuoteId, $response['setShippingMethodsOnCart']['cart']['cart_id']); + + // TODO: check shipping method code and description + } + + // TODO: cover all other cases +} From a30654fb794e4517cdfec07ac431824e2243dec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Szyma=C5=84ski?= <bartlomiej.szymanski@bold.net.pl> Date: Fri, 2 Nov 2018 14:29:17 +0100 Subject: [PATCH 0452/1158] Replace GraphQlInputException on \LogicException --- .../Model/LayerFilterItemTypeResolverComposite.php | 4 +--- .../Model/ProductLinkTypeResolverComposite.php | 4 +--- app/code/Magento/EavGraphQl/Model/Resolver/Query/Type.php | 7 +------ 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/LayerFilterItemTypeResolverComposite.php b/app/code/Magento/CatalogGraphQl/Model/LayerFilterItemTypeResolverComposite.php index 20e5590117556..e04b5d1bf67ff 100644 --- a/app/code/Magento/CatalogGraphQl/Model/LayerFilterItemTypeResolverComposite.php +++ b/app/code/Magento/CatalogGraphQl/Model/LayerFilterItemTypeResolverComposite.php @@ -43,9 +43,7 @@ public function resolveType(array $data) : string } } if (empty($resolvedType)) { - throw new GraphQlInputException( - __('Concrete type for %1 not implemented', ['ProductLinksInterface']) - ); + throw new \LogicException('Cannot resolve layered filter type'); } } } diff --git a/app/code/Magento/CatalogGraphQl/Model/ProductLinkTypeResolverComposite.php b/app/code/Magento/CatalogGraphQl/Model/ProductLinkTypeResolverComposite.php index 937e3921758dc..5f6d1a65519f8 100644 --- a/app/code/Magento/CatalogGraphQl/Model/ProductLinkTypeResolverComposite.php +++ b/app/code/Magento/CatalogGraphQl/Model/ProductLinkTypeResolverComposite.php @@ -50,9 +50,7 @@ public function resolveType(array $data) : string } if (!$resolvedType) { - throw new GraphQlInputException( - __('Concrete type for %1 not implemented', ['ProductLinksInterface']) - ); + throw new \LogicException('Cannot resolve type'); } } } diff --git a/app/code/Magento/EavGraphQl/Model/Resolver/Query/Type.php b/app/code/Magento/EavGraphQl/Model/Resolver/Query/Type.php index cbea3a86bbddd..b1d7aae5df101 100644 --- a/app/code/Magento/EavGraphQl/Model/Resolver/Query/Type.php +++ b/app/code/Magento/EavGraphQl/Model/Resolver/Query/Type.php @@ -71,12 +71,7 @@ public function getType(string $attributeCode, string $entityType) : string try { $type = $this->typeProcessor->translateTypeName($type); } catch (\InvalidArgumentException $exception) { - throw new GraphQlInputException( - __('Type %1 has no internal representation declared.', [$type]), - null, - 0, - false - ); + throw new \LogicException('Cannot resolve EAV type'); } } else { $type = $type === 'double' ? 'float' : $type; From 12e0c534e70632deff7e177fa716b79dfbbf83ba Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Fri, 2 Nov 2018 16:55:05 +0300 Subject: [PATCH 0453/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fix static test --- app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index a2cbc5087cd12..c530ba4785ad9 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -146,10 +146,10 @@ class Toolbar extends \Magento\Framework\View\Element\Template * @param \Magento\Framework\Url\EncoderInterface $urlEncoder * @param ProductList $productListHelper * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper + * @param array $data * @param ToolbarMemorizer|null $toolbarMemorizer * @param \Magento\Framework\App\Http\Context|null $httpContext * @param \Magento\Framework\Data\Form\FormKey|null $formKey - * @param array $data * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ From 144ea18392229aef98c5a21165fba106bd97840d Mon Sep 17 00:00:00 2001 From: Lars Roettig <l.roettig@techdivision.com> Date: Fri, 2 Nov 2018 15:34:08 +0100 Subject: [PATCH 0454/1158] CodeReviewChange --- .../Magento/Store/Model/Config/Importer/Processor/Create.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php index 3142955ac5988..9d1a7a38ede68 100644 --- a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php +++ b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php @@ -177,7 +177,10 @@ private function createGroups(array $items, array $data) ); $group = $this->groupFactory->create(); - $group->setRootCategoryId(0); + if (!isset($groupData['root_categry_id'])) { + $groupData['root_categry_id'] = 0; + } + $group->setData($groupData); $group->getResource()->save($group); From 9498e05885b865a6c4589221ebf20491360d41a7 Mon Sep 17 00:00:00 2001 From: Joan He <johe@adobe.com> Date: Fri, 2 Nov 2018 09:44:30 -0500 Subject: [PATCH 0455/1158] MAGETWO-95659: Fix and Unskip MTF OnePageCheckoutOfflinePaymentMethodsTest --- .../Test/Constraint/AssertCartIsEmpty.php | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php index c2839651b582f..22a6136737089 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php @@ -6,7 +6,6 @@ namespace Magento\Checkout\Test\Constraint; -use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Page\CheckoutCart; use Magento\Mtf\Client\BrowserInterface; use Magento\Mtf\Constraint\AbstractConstraint; @@ -42,10 +41,12 @@ public function processAssert(CheckoutCart $checkoutCart, BrowserInterface $brow ); $cartEmptyBlock->clickLinkToMainPage(); - \PHPUnit\Framework\Assert::assertEquals( + $this->assertUrlEqual( $_ENV['app_frontend_url'], $browser->getUrl(), - 'Wrong link to main page on empty cart page.' + true, + 'Wrong link to main page on empty cart page: expected - ' . $_ENV['app_frontend_url'] + . ', actural - ' . $browser->getUrl() ); } @@ -58,4 +59,27 @@ public function toString() { return 'Shopping Cart is empty.'; } + + /** + * Asserts that two urls are equal + * + * @param string $url1 + * @param string $url2 + * @param bool $ignoreScheme + * @param string $message + * @return void + */ + private function assertUrlEqual($expectedUrl, $actualUrl, $ignoreScheme = false, $message = '') + { + $urlArray1 = parse_url($expectedUrl); + $urlArray2 = parse_url($actualUrl); + if ($ignoreScheme) { + unset($urlArray1['scheme']); + unset($urlArray2['scheme']); + } + \PHPUnit\Framework\Assert::assertTrue( + $urlArray1 === $urlArray2, + $message + ); + } } From c333367742e668ea824c09675eb059fb246181a2 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Fri, 2 Nov 2018 17:09:46 +0200 Subject: [PATCH 0456/1158] #13157 - Last Ordered Items block - bad js code --- .../view/frontend/templates/reorder/sidebar.phtml | 14 +++++++++----- .../frontend/web/js/view/last-ordered-items.js | 12 ++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml b/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml index 5ecf1ebe893bc..370e034ead64a 100644 --- a/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml +++ b/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml @@ -26,14 +26,18 @@ <ol id="cart-sidebar-reorder" class="product-items product-items-names" data-bind="foreach: lastOrderedItems().items"> <li class="product-item"> - <div class="field item choice no-display" data-bind="css: {'no-display': !is_saleable}"> + <div class="field item choice"> <label class="label" data-bind="attr: {'for': 'reorder-item-' + id}"> <span><?= /* @escapeNotVerified */ __('Add to Cart') ?></span> </label> <div class="control"> <input type="checkbox" name="order_items[]" - data-bind="attr: {id: 'reorder-item-' + id, value: id}" - title="<?= /* @escapeNotVerified */ __('Add to Cart') ?>" + data-bind="attr: { + id: 'reorder-item-' + id, + value: id, + title: is_saleable ? '<?= /* @escapeNotVerified */ __('Add to Cart') ?>' : '<?= /* @escapeNotVerified */ __('Product is not salable.') ?>' + }, + disable: !is_saleable" class="checkbox" data-validate='{"validate-one-checkbox-required-by-name": true}'/> </div> </div> @@ -46,8 +50,8 @@ </ol> <div id="cart-sidebar-reorder-advice-container"></div> <div class="actions-toolbar"> - <div class="primary no-display" - data-bind="css: {'no-display': !lastOrderedItems().isShowAddToCart}"> + <div class="primary" + data-bind="visible: lastOrderedItems.isShowAddToCart"> <button type="submit" title="<?= /* @escapeNotVerified */ __('Add to Cart') ?>" class="action tocart primary"> <span><?= /* @escapeNotVerified */ __('Add to Cart') ?></span> </button> diff --git a/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js b/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js index f393cc3fcd3bc..9897666653df9 100644 --- a/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js +++ b/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js @@ -12,18 +12,14 @@ define([ return Component.extend({ /** @inheritdoc */ initialize: function () { - var isShowAddToCart = false, - item; + var isShowAddToCart; this._super(); this.lastOrderedItems = customerData.get('last-ordered-items'); - for (item in this.lastOrderedItems.items) { - if (item['is_saleable']) { - isShowAddToCart = true; - break; - } - } + isShowAddToCart = _.some(this.lastOrderedItems().items, { + 'is_saleable': true + }); this.lastOrderedItems.isShowAddToCart = isShowAddToCart; } From 0a6c0b5a792dbba00295bea9b9b902c7b9598205 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Fri, 2 Nov 2018 17:15:09 +0200 Subject: [PATCH 0457/1158] graphQl: removed multishipping implementation, fixed namespaces --- .../SetShippingAddressOnCart.php} | 19 ++- .../Resolver/SetShippingAddressesOnCart.php | 101 +++++++++++++ .../MultiShipping.php | 76 ---------- .../MultiShipping/ShippingItemsMapper.php | 43 ------ .../SetShippingAddressesOnCart.php | 133 ------------------ .../Magento/QuoteGraphQl/etc/schema.graphqls | 3 +- 6 files changed, 117 insertions(+), 258 deletions(-) rename app/code/Magento/QuoteGraphQl/Model/{Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php => Cart/SetShippingAddressOnCart.php} (85%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php similarity index 85% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php rename to app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php index feeb333683f76..43e58bb807672 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/SingleShipping.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart; +namespace Magento\QuoteGraphQl\Model\Cart; use Magento\Authorization\Model\UserContextInterface; use Magento\Customer\Api\Data\AddressInterface; @@ -16,7 +16,12 @@ use Magento\Quote\Model\ShippingAddressManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; -class SingleShipping +/** + * Class SetShippingAddressOnCart + * + * Set shipping address for a specified shopping cart + */ +class SetShippingAddressOnCart { /** * @var ShippingAddressManagementInterface @@ -51,11 +56,17 @@ public function __construct( /** * @param ContextInterface $context * @param int $cartId - * @param array $shippingAddress + * @param array $shippingAddresses * @return void */ - public function setAddress(ContextInterface $context, int $cartId, array $shippingAddress): void + public function setAddresses(ContextInterface $context, int $cartId, array $shippingAddresses): void { + if (count($shippingAddresses) > 1) { + throw new GraphQlInputException( + __('Multiple address does not allowed here!') + ); + } + $shippingAddress = current($shippingAddresses); $customerAddressId = $shippingAddress['customer_address_id'] ?? null; $addressInput = $shippingAddress['address'] ?? null; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php new file mode 100644 index 0000000000000..fcb4255a75eb7 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php @@ -0,0 +1,101 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use Magento\Quote\Model\ShippingAddressManagementInterface; +use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; +use Magento\QuoteGraphQl\Model\Cart\SetShippingAddressOnCart; + +/** + * Class SetShippingAddressesOnCart + * + * Mutation resolver for setting shipping addresses for shopping cart + */ +class SetShippingAddressesOnCart implements ResolverInterface +{ + /** + * @var MaskedQuoteIdToQuoteIdInterface + */ + private $maskedQuoteIdToQuoteId; + + /** + * @var SetShippingAddressOnCart + */ + private $setShippingAddressOnCart; + + /** + * @var ShippingAddressManagementInterface + */ + private $shippingAddressManagement; + + /** + * @var GetCartForUser + */ + private $getCartForUser; + + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + * @param SetShippingAddressOnCart $setShippingAddressOnCart + * @param ShippingAddressManagementInterface $shippingAddressManagement + * @param GetCartForUser $getCartForUser + * @param ArrayManager $arrayManager + */ + public function __construct( + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, + SetShippingAddressOnCart $setShippingAddressOnCart, + ShippingAddressManagementInterface $shippingAddressManagement, + GetCartForUser $getCartForUser, + ArrayManager $arrayManager + ) { + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->setShippingAddressOnCart = $setShippingAddressOnCart; + $this->shippingAddressManagement = $shippingAddressManagement; + $this->getCartForUser = $getCartForUser; + $this->arrayManager = $arrayManager; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $shippingAddresses = $this->arrayManager->get('input/shipping_addresses', $args); + $maskedCartId = $this->arrayManager->get('input/cart_id', $args); + + if (!$maskedCartId) { + throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); + } + if (!$shippingAddresses) { + throw new GraphQlInputException(__('Required parameter "shipping_addresses" is missing')); + } + + $maskedCartId = $args['input']['cart_id']; + $cart = $this->getCartForUser->execute($maskedCartId, $context->getUserId()); + $cartId = (int)$cart->getEntityId(); + + $this->setShippingAddressOnCart->setAddresses($context, $cartId, $shippingAddresses); + + return [ + 'cart' => [ + 'cart_id' => $maskedCartId, + 'model' => $cart + ] + ]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php deleted file mode 100644 index 318fd9361af5a..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart; - -use Magento\Authorization\Model\UserContextInterface; -use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; -use Magento\Multishipping\Model\Checkout\Type\Multishipping as MultishippingModel; -use Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\MultiShipping\ShippingItemsMapper; - -class MultiShipping -{ - /** - * @var MultishippingModel - */ - private $multishippingModel; - - /** - * @var ShippingItemsMapper - */ - private $shippingItemsInformationMapper; - - /** - * @param MultishippingModel $multishippingModel - * @param ShippingItemsMapper $shippingItemsInformationMapper - */ - public function __construct( - MultishippingModel $multishippingModel, - ShippingItemsMapper $shippingItemsInformationMapper - ) { - $this->multishippingModel = $multishippingModel; - $this->shippingItemsInformationMapper = $shippingItemsInformationMapper; - } - - /** - * @param ContextInterface $context - * @param int $cartId - * @param array $shippingAddresses - */ - public function setAddresses(ContextInterface $context, int $cartId, array $shippingAddresses): void - { - if ((!$context->getUserId()) || $context->getUserType() == UserContextInterface::USER_TYPE_GUEST) { - throw new GraphQlAuthorizationException( - __( - 'Multishipping allowed only for authorized customers' - ) - ); - } - - $shippingItemsInformation = []; - foreach ($shippingAddresses as $shippingAddress) { - $customerAddressId = $shippingAddress['customer_address_id'] ?? null; - $cartItems = $shippingAddress['cart_items'] ?? null; - if (!$customerAddressId) { - throw new GraphQlInputException(__('Parameter "customer_address_id" is required for multishipping')); - } - if (!$cartItems) { - throw new GraphQlInputException(__('Parameter "cart_items" is required for multishipping')); - } - - $shippingItemsInformation = array_merge( - $shippingItemsInformation, - $this->shippingItemsInformationMapper->map($shippingAddress) - ); - } - - //TODO: multishipping model works with session. Do we need to avoid it? - $this->multishippingModel->setShippingItemsInformation($shippingItemsInformation); - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php deleted file mode 100644 index ad5207814db7c..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressOnCart/MultiShipping/ShippingItemsMapper.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\MultiShipping; - -/** - * Shipping address to shipping items mapper - */ -class ShippingItemsMapper -{ - - /** - * Converts shipping address input array into shipping items information array - * Array structure: - * array( - * $cartItemId => array( - * 'qty' => $qty, - * 'address' => $customerAddressId - * ) - * ) - * - * @param array $shippingAddress - * @return array - */ - public function map(array $shippingAddress): array - { - $shippingItemsInformation = []; - foreach ($shippingAddress['cart_items'] as $cartItem) { - $shippingItemsInformation[] = [ - $cartItem['cart_item_id'] => [ - 'qty' => $cartItem['quantity'], - 'address' => $shippingAddress['customer_address_id'] - ] - ]; - } - - return $shippingItemsInformation; - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php deleted file mode 100644 index 7ffa6c4950b3d..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/SetShippingAddressesOnCart.php +++ /dev/null @@ -1,133 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\ShippingAddress; - -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; -use Magento\Quote\Model\ShippingAddressManagementInterface; -use Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\MultiShipping; -use Magento\QuoteGraphQl\Model\Resolver\ShippingAddress\SetShippingAddressOnCart\SingleShipping; - -/** - * @inheritdoc - */ -class SetShippingAddressesOnCart implements ResolverInterface -{ - /** - * @var MaskedQuoteIdToQuoteIdInterface - */ - private $maskedQuoteIdToQuoteId; - - /** - * @var MultiShipping - */ - private $multiShipping; - - /** - * @var SingleShipping - */ - private $singleShipping; - - /** - * @var ShippingAddressManagementInterface - */ - private $shippingAddressManagement; - - /** - * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId - * @param MultiShipping $multiShipping - * @param SingleShipping $singleShipping - * @param ShippingAddressManagementInterface $shippingAddressManagement - */ - public function __construct( - MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - MultiShipping $multiShipping, - SingleShipping $singleShipping, - ShippingAddressManagementInterface $shippingAddressManagement - ) { - $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->multiShipping = $multiShipping; - $this->singleShipping = $singleShipping; - $this->shippingAddressManagement = $shippingAddressManagement; - } - - /** - * @inheritdoc - */ - public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) - { - if (!isset($args['input']['cart_id'])) { - throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); - } - if (!isset($args['input']['shipping_addresses'])) { - throw new GraphQlInputException(__('Required parameter "shipping_addresses" is missing')); - } - - $shippingAddressesInput = $args['input']['shipping_addresses']; - $maskedCartId = $args['input']['cart_id']; - $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId); - - if (count($shippingAddressesInput) === 1) { - $this->singleShipping->setAddress($context, $cartId, current($shippingAddressesInput)); - } else { - $this->multiShipping->setAddresses($context, $cartId, $shippingAddressesInput); - } - - //TODO: implement Cart object in the separate resolver - $shippingAddress = $this->shippingAddressManagement->get($cartId); - return [ - 'cart' => [ - 'applied_coupon' => [ - 'code' => '' - ], - 'addresses' => [[ - 'firstname' => $shippingAddress->getFirstname(), - 'lastname' => $shippingAddress->getLastname(), - 'company' => $shippingAddress->getCompany(), - 'street' => $shippingAddress->getStreet(), - 'city' => $shippingAddress->getCity(), - 'region' => [ - 'code' => $shippingAddress->getRegionCode(), - 'label' => $shippingAddress->getRegion() - ], - 'country' => [ - 'code' => $shippingAddress->getCountryId(), - 'label' => '' - ], - 'postcode' => $shippingAddress->getPostcode(), - 'telephone' => $shippingAddress->getTelephone(), - 'address_type' => 'SHIPPING', - 'selected_shipping_method' => [ - 'code' => 'test', - 'label' => 'test', - 'free_shipping' => 'test', - 'error_message' => 'test' - ], - 'available_shipping_methods' => [[ - 'code' => 'test', - 'label' => 'test', - 'free_shipping' => 'test', - 'error_message' => 'test' - ]], - 'items_weight' => [0], - 'customer_notes' => $shippingAddress->getLastname(), - 'cart_items' => [[ - 'cart_item_id' => '', - 'quantity' => 0 - ]], - 'applied_coupon' => [ - 'code' => '' - ] - ]] - ] - ]; - } -} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 7312c15e06580..017b1f8119829 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -9,11 +9,10 @@ type Mutation { createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") - setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ShippingAddress\\SetShippingAddressesOnCart") + setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingAddressesOnCart") createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveCouponFromCart") - setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingMethodsOnCart") addSimpleProductsToCart(input: AddSimpleProductsToCartInput): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") From e18df69004ef25f53ed927e953cc5fce0191bf84 Mon Sep 17 00:00:00 2001 From: Vladyslav Podorozhnyi <v.podorozhnyi@ism-ukraine.com> Date: Fri, 2 Nov 2018 17:26:27 +0200 Subject: [PATCH 0458/1158] magento/magento2#14007: "Use in Layered Navigation: Filterable (no results)" not working for `Price` attribute. - adjust comment for "Use in Layered Navigation: Filterable (no results)" property to make it more understandable --- .../Tab/Front/ProductAttributeFormBuildFrontTabObserver.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/LayeredNavigation/Observer/Edit/Tab/Front/ProductAttributeFormBuildFrontTabObserver.php b/app/code/Magento/LayeredNavigation/Observer/Edit/Tab/Front/ProductAttributeFormBuildFrontTabObserver.php index 1bb601e3a4ebd..ce618f97883b0 100644 --- a/app/code/Magento/LayeredNavigation/Observer/Edit/Tab/Front/ProductAttributeFormBuildFrontTabObserver.php +++ b/app/code/Magento/LayeredNavigation/Observer/Edit/Tab/Front/ProductAttributeFormBuildFrontTabObserver.php @@ -60,7 +60,11 @@ public function execute(\Magento\Framework\Event\Observer $observer) 'name' => 'is_filterable', 'label' => __("Use in Layered Navigation"), 'title' => __('Can be used only with catalog input type Yes/No, Dropdown, Multiple Select and Price'), - 'note' => __('Can be used only with catalog input type Yes/No, Dropdown, Multiple Select and Price.'), + 'note' => __( + 'Can be used only with catalog input type Yes/No, Dropdown, Multiple Select and Price. + <br>Price is not compatible with <b>\'Filterable (no results)\'</b> option - + it will make no affect on Price filter.' + ), 'values' => [ ['value' => '0', 'label' => __('No')], ['value' => '1', 'label' => __('Filterable (with results)')], From 43e2c4dae51a62e169eed7ae6761f565d6780692 Mon Sep 17 00:00:00 2001 From: StasKozar <staskozar.91@gmail.com> Date: Fri, 2 Nov 2018 17:31:24 +0200 Subject: [PATCH 0459/1158] magento/magento2#18990: Shipping address is not validated in checkout when proceeding step as logged in user with default shipping address --- .../Checkout/Test/Mftf/Data/CountryData.xml | 22 ++++++++ ...frontCustomerCheckoutWithoutRegionTest.xml | 55 +++++++++++++++++++ .../view/frontend/web/js/view/shipping.js | 15 ++++- .../GeneralConfigurationActionGroup.xml | 13 +++++ .../Test/Mftf/Section/GeneralSection.xml | 5 ++ .../Customer/Test/Mftf/Data/CustomerData.xml | 13 +++++ 6 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml b/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml index 26bc6ff641a9c..dc82932ec5ca7 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml @@ -13,4 +13,26 @@ <item>Bahamas</item> </array> </entity> + <entity name="DefaultCountriesWithRequiredRegions" type="countryArray"> + <array key="country"> + <item>Australia</item> + <item>Brazil</item> + <item>Canada</item> + <item>Croatia</item> + <item>Estonia</item> + <item>India</item> + <item>Latvia</item> + <item>Lithuania</item> + <item>Romania</item> + <item>Spain</item> + <item>Switzerland</item> + <item>United States</item> + <item>Australia</item> + </array> + </entity> + <entity name="CustomCountryWithRequiredRegion" type="countryArray"> + <array key="country"> + <item>United Kingdom</item> + </array> + </entity> </entities> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml new file mode 100644 index 0000000000000..0cc0dcf38e312 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCustomerCheckoutWithoutRegionTest"> + <annotations> + <features value="Checkout"/> + <stories value="Checkout via the Admin"/> + <title value="Shipping address is not validated in checkout when proceeding step as logged in user with default shipping address"/> + <description value="Shouldn't be able to place an order as a customer without state if it's required."/> + <severity value="CRITICAL"/> + <testCaseId value="#"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Simple_GB_Customer" stepKey="createCustomer"/> + <actionGroup stepKey="loginToAdminPanel" ref="LoginAsAdmin"/> + <actionGroup ref="SelectCountriesWithRequiredRegion" stepKey="setCustomCountryWithRequiredRegion"> + <argument name="countries" value="CustomCountryWithRequiredRegion"/> + </actionGroup> + </before> + <after> + <actionGroup ref="SelectCountriesWithRequiredRegion" stepKey="setDefaultCountriesWithRequiredRegion"> + <argument name="countries" value="DefaultCountriesWithRequiredRegions"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + </after> + + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$createCustomer$$" /> + </actionGroup> + + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="navigateToCheckoutPage"/> + + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNextButton"/> + <see selector="{{StorefrontMessagesSection.error}}" userInput='Please specify a regionId in shipping address.' stepKey="seeErrorMessages"/> + </test> +</tests> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js index 395d15bc02f36..6ac805f72f78d 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -265,7 +265,12 @@ define([ addressData, loginFormSelector = 'form[data-role=email-with-possible-login]', emailValidationResult = customer.isLoggedIn(), - field; + field, + countryIndexedOptions = registry.get( + this.parentName + '.shippingAddress.shipping-address-fieldset.country_id' + ).indexedOptions, + option = countryIndexedOptions[quote.shippingAddress().countryId], + messageContainer = registry.get('checkout.errors').messageContainer; if (!quote.shippingMethod()) { this.errorValidationMessage( @@ -318,6 +323,14 @@ define([ shippingAddress['save_in_address_book'] = 1; } selectShippingAddress(shippingAddress); + } else if (customer.isLoggedIn() + && option + && option['is_region_required'] + && !quote.shippingAddress().region + ) { + messageContainer.addErrorMessage({message: $t('Please specify a regionId in shipping address.')}); + + return false; } if (!emailValidationResult) { diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml index fca48dfb49cfb..f05cf5be3448e 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml @@ -37,4 +37,17 @@ <click selector="#save" stepKey="saveConfig"/> <waitForPageLoad stepKey="waitForSavingConfig"/> </actionGroup> + + <actionGroup name="SelectCountriesWithRequiredRegion"> + <arguments> + <argument name="countries" type="countryArray"/> + </arguments> + <amOnPage url="{{AdminConfigGeneralPage.url}}" stepKey="navigateToAdminConfigGeneralPage"/> + <conditionalClick selector="{{StateOptionsSection.stateOptions}}" dependentSelector="{{StateOptionsSection.countriesWithRequiredRegions}}" visible="false" stepKey="expandStateOptionsTab" /> + <waitForAjaxLoad stepKey="waitForAjax"/> + <scrollTo selector="{{StateOptionsSection.countriesWithRequiredRegions}}" stepKey="scrollToForm"/> + <selectOption selector="{{StateOptionsSection.countriesWithRequiredRegions}}" parameterArray="[{{countries.country}}]" stepKey="selectCountriesWithRequiredRegion"/> + <click selector="#save" stepKey="saveConfig"/> + <waitForPageLoad stepKey="waitForSavingConfig"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml index 88532dc091f45..66b40f74d8e98 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml @@ -38,4 +38,9 @@ <element name="countryOptionsOpen" type="button" selector="#general_country-head.open"/> <element name="topDestinations" type="select" selector="#general_country_destinations"/> </section> + <section name="StateOptionsSection"> + <element name="stateOptions" type="button" selector="#general_region-head"/> + <element name="countriesWithRequiredRegions" type="select" selector="#general_region_state_required"/> + <element name="allowToChooseState" type="select" selector="general_region_display_all"/> + </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml index 6f5ade53e6790..a61871105a5f3 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml @@ -102,4 +102,17 @@ <data key="website_id">0</data> <requiredEntity type="address">US_Address_CA</requiredEntity> </entity> + <entity name="Simple_GB_Customer" type="customer"> + <data key="group_id">0</data> + <data key="default_billing">true</data> + <data key="default_shipping">true</data> + <data key="email" unique="prefix">Jane.Doe@example.com</data> + <data key="firstname">Jane</data> + <data key="lastname">Doe</data> + <data key="fullname">Jane Doe</data> + <data key="password">pwdTest123!</data> + <data key="store_id">0</data> + <data key="website_id">0</data> + <requiredEntity type="address">UK_Not_Default_Address</requiredEntity> + </entity> </entities> From c8941f1d13a82e0c3d1c65dbf262a5e295933f3f Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak <Aliaksei_Manenak@epam.com> Date: Fri, 2 Nov 2018 18:47:41 +0300 Subject: [PATCH 0460/1158] MAGETWO-61478: Number of Products displayed per page not retained when visiting a different category - Fix statics. --- app/code/Magento/Catalog/Controller/Category/View.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Controller/Category/View.php b/app/code/Magento/Catalog/Controller/Category/View.php index 43f25c58a70dd..2088bb5ea77cd 100644 --- a/app/code/Magento/Catalog/Controller/Category/View.php +++ b/app/code/Magento/Catalog/Controller/Category/View.php @@ -208,7 +208,7 @@ public function execute() if ($layoutUpdates && is_array($layoutUpdates)) { foreach ($layoutUpdates as $layoutUpdate) { $page->addUpdate($layoutUpdate); - $page->addPageLayoutHandles(['layout_update' => md5($layoutUpdate)], null, false); + $page->addPageLayoutHandles(['layout_update' => sha1($layoutUpdate)], null, false); } } From 4ec4c0e1f390c987b6db7efd799cb0da74df1770 Mon Sep 17 00:00:00 2001 From: Joan He <johe@adobe.com> Date: Fri, 2 Nov 2018 11:54:18 -0500 Subject: [PATCH 0461/1158] MAGETWO-95660: Fix and Unskip MTF OnePageCheckoutTest --- .../Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml index 5c05d4a840009..0edd8f4183f30 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml @@ -7,7 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Checkout\Test\TestCase\OnePageCheckoutTest" summary="OnePageCheckout within Offline Payment Methods" ticketId="MAGETWO-27485"> - <variation name="OnePageCheckoutUsingSingInLink" summary="Login during checkout using 'Sign In' link" ticketId="MAGETWO-42547"> + <variation name="OnePageCheckoutUsingSignInLink" summary="Login during checkout using 'Sign In' link" ticketId="MAGETWO-42547"> <data name="tag" xsi:type="string">severity:S1</data> <data name="products/0" xsi:type="string">catalogProductSimple::default</data> <data name="customer/dataset" xsi:type="string">customer_UK_US_addresses</data> @@ -49,10 +49,6 @@ <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderAddresses" /> - <!-- MAGETWO-94169 --> - <data name="tag" xsi:type="string">stable:no</data> - <data name="issue" xsi:type="string">MAGETWO-94169: [MTF] - OnePageCheckoutUsingNonDefaultAddress_0 fails on 2.3-develop</data> - <!-- MAGETWO-94169 --> </variation> <variation name="OnePageCheckoutUsingNewAddress" summary="Checkout as Customer using New address" ticketId="MAGETWO-42601"> <data name="tag" xsi:type="string">severity:S1</data> From 90cf2e0da44ba17b8d21307e062be80391d402e5 Mon Sep 17 00:00:00 2001 From: Sergii Ivashchenko <serg.ivashchenko@gmail.com> Date: Fri, 2 Nov 2018 17:09:40 +0000 Subject: [PATCH 0462/1158] Removed unnecessary empty line --- lib/internal/Magento/Framework/Translate.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Translate.php b/lib/internal/Magento/Framework/Translate.php index 98ba6c0d718c3..ff1bf99162a8a 100644 --- a/lib/internal/Magento/Framework/Translate.php +++ b/lib/internal/Magento/Framework/Translate.php @@ -454,7 +454,6 @@ private function getThemeTranslationFilesList($locale): array return $translationFiles; } - /** * Retrieve translation file for theme * From 4a945f2807c391d6a5aca92ffb7cd4a09f9aa2f0 Mon Sep 17 00:00:00 2001 From: Abrar pathan <abrarkhan@krishtechnolabs.com> Date: Sat, 3 Nov 2018 11:58:43 +0530 Subject: [PATCH 0463/1158] fixed-18887-notifications-counter --- .../css/source/module/header/actions-group/_notifications.less | 1 + 1 file changed, 1 insertion(+) diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less index c9c97930297cb..93fc0d3eb4948 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less @@ -103,6 +103,7 @@ padding: .3em .5em; position: absolute; top: 50%; + width: 18px; } } From 73ff7cbc55cb1bbde88a96421daa5410f1fdd8c9 Mon Sep 17 00:00:00 2001 From: Mahesh Singh <mahesh721@webkul.com> Date: Sun, 4 Nov 2018 20:33:10 +0530 Subject: [PATCH 0464/1158] Fixed Product Tax total on PDF for 2.3, Reference of PL #18649 --- app/code/Magento/Weee/Model/Sales/Pdf/Weee.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php b/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php index fa71e81281763..65480047f2f05 100644 --- a/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php +++ b/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php @@ -70,4 +70,17 @@ public function getTotalsForDisplay() return $totals; } + + /** + * Check if we can display Weee total information in PDF + * + * @return bool + */ + public function canDisplay() + { + $items = $this->getSource()->getAllItems(); + $store = $this->getSource()->getStore(); + $amount = $this->_weeeData->getTotalAmounts($items, $store); + return $this->getDisplayZero() === 'true' || $amount != 0; + } } From 5fa66213fa852793694b4aee831bb93969bff5d0 Mon Sep 17 00:00:00 2001 From: Vasilii Burlacu <v.burlacu@atwix.com> Date: Sun, 4 Nov 2018 17:20:03 +0200 Subject: [PATCH 0465/1158] magento/magento2:#18979 - API: Bundle Product Option Repository Delete method removes incorrect option - Fixed failed unit tests --- .../Magento/Bundle/Model/OptionRepository.php | 11 +-- .../Test/Unit/Model/OptionRepositoryTest.php | 74 +++++++++++++++++-- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Bundle/Model/OptionRepository.php b/app/code/Magento/Bundle/Model/OptionRepository.php index a4d579a44174a..46c44c83b5bb5 100644 --- a/app/code/Magento/Bundle/Model/OptionRepository.php +++ b/app/code/Magento/Bundle/Model/OptionRepository.php @@ -106,17 +106,18 @@ public function get($sku, $optionId) $productLinks = $this->linkManagement->getChildren($product->getSku(), $optionId); - /** @var \Magento\Bundle\Api\Data\OptionInterface $option */ + /** @var \Magento\Bundle\Api\Data\OptionInterface $optionDataObject */ $optionDataObject = $this->optionFactory->create(); $this->dataObjectHelper->populateWithArray( $optionDataObject, $option->getData(), \Magento\Bundle\Api\Data\OptionInterface::class ); - $optionDataObject->setOptionId($option->getId()) - ->setTitle($option->getTitle() === null ? $option->getDefaultTitle() : $option->getTitle()) - ->setSku($product->getSku()) - ->setProductLinks($productLinks); + + $optionDataObject->setOptionId($option->getId()); + $optionDataObject->setTitle($option->getTitle() === null ? $option->getDefaultTitle() : $option->getTitle()); + $optionDataObject->setSku($product->getSku()); + $optionDataObject->setProductLinks($productLinks); return $optionDataObject; } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php b/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php index b4a466b413af0..c579d8289d1b6 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php @@ -8,6 +8,7 @@ namespace Magento\Bundle\Test\Unit\Model; use Magento\Bundle\Model\OptionRepository; +use Magento\Framework\Exception\NoSuchEntityException; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -84,7 +85,7 @@ protected function setUp() ->getMock(); $this->optionResourceMock = $this->createPartialMock( \Magento\Bundle\Model\ResourceModel\Option::class, - ['delete', '__wakeup', 'save', 'removeOptionSelections'] + ['get', 'delete', '__wakeup', 'save', 'removeOptionSelections'] ); $this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); $this->linkManagementMock = $this->createMock(\Magento\Bundle\Api\ProductLinkManagementInterface::class); @@ -227,32 +228,91 @@ public function testDeleteThrowsExceptionIfCannotDelete() $this->model->delete($optionMock); } + /** + * Test successful delete action for given $optionId + */ public function testDeleteById() { $productSku = 'sku'; $optionId = 100; - $productMock = $this->createMock(\Magento\Catalog\Api\Data\ProductInterface::class); + + $optionMock = $this->createMock(\Magento\Bundle\Model\Option::class); + $optionMock->expects($this->exactly(2)) + ->method('getId') + ->willReturn($optionId); + + $optionMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'title' => 'Option title', + 'option_id' => $optionId + ]); + + $this->optionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($optionMock); + + $productMock = $this->createPartialMock( + \Magento\Catalog\Model\Product::class, + ['getTypeId', 'getTypeInstance', 'getStoreId', 'getPriceType', '__wakeup', 'getSku'] + ); $productMock->expects($this->once()) ->method('getTypeId') ->willReturn(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE); - $this->productRepositoryMock->expects($this->once()) + $productMock->expects($this->exactly(2))->method('getSku')->willReturn($productSku); + + $this->productRepositoryMock + ->expects($this->once()) ->method('get') ->with($productSku) ->willReturn($productMock); + $optCollectionMock = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); + $optCollectionMock->expects($this->once())->method('getItemById')->with($optionId)->willReturn($optionMock); + $this->typeMock->expects($this->once()) + ->method('getOptionsCollection') + ->with($productMock) + ->willReturn($optCollectionMock); + + $this->assertTrue($this->model->deleteById($productSku, $optionId)); + } + + /** + * Tests if NoSuchEntityException thrown when provided $optionId not found + */ + public function testDeleteByIdException() { + $productSku = 'sku'; + $optionId = null; + $optionMock = $this->createMock(\Magento\Bundle\Model\Option::class); + $optionMock->expects($this->exactly(1)) + ->method('getId') + ->willReturn($optionId); + + $productMock = $this->createPartialMock( + \Magento\Catalog\Model\Product::class, + ['getTypeId', 'getTypeInstance', 'getStoreId', 'getPriceType', '__wakeup', 'getSku'] + ); + $productMock->expects($this->once()) + ->method('getTypeId') + ->willReturn(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE); + + $this->productRepositoryMock + ->expects($this->once()) + ->method('get') + ->with($productSku) + ->willReturn($productMock); $optCollectionMock = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); + $optCollectionMock->expects($this->once())->method('getItemById')->with($optionId)->willReturn($optionMock); $this->typeMock->expects($this->once()) ->method('getOptionsCollection') ->with($productMock) ->willReturn($optCollectionMock); - $optCollectionMock->expects($this->once())->method('setIdFilter')->with($optionId)->willReturnSelf(); - $optCollectionMock->expects($this->once())->method('getFirstItem')->willReturn($optionMock); + $this->expectException(NoSuchEntityException::class); - $this->optionResourceMock->expects($this->once())->method('delete')->with($optionMock)->willReturnSelf(); - $this->assertTrue($this->model->deleteById($productSku, $optionId)); + $this->model->deleteById($productSku, $optionId); } /** From f06056a040a22d49a580fba331cad11799267272 Mon Sep 17 00:00:00 2001 From: Artem Klimov <art.klimoff@gmail.com> Date: Mon, 5 Nov 2018 00:32:38 +0200 Subject: [PATCH 0466/1158] Sort schema field for test cases --- .../Framework/GraphQl/Config/GraphQlReaderTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php b/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php index 8583dcf3e4cd2..3d3372429123a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php @@ -191,6 +191,16 @@ enumValues(includeDeprecated: true) { $mergedSchemaResponseFields = array_merge($schemaResponseFieldsFirstHalf, $schemaResponseFieldsSecondHalf); foreach ($expectedOutput as $searchTerm) { + $sortFields = ['inputFields', 'fields']; + foreach ($sortFields as $sortField) { + isset($searchTerm[$sortField]) && is_array($searchTerm[$sortField]) + ? usort($searchTerm[$sortField], function($a, $b) { + $cmpField = 'name'; + return isset($a[$cmpField]) && isset($b[$cmpField]) + ? strcmp($a[$cmpField], $b[$cmpField]) : 0; + }) : null; + } + $this->assertTrue( (in_array($searchTerm, $mergedSchemaResponseFields)), 'Missing type in the response' From 0f575bce67a6dbc4fd9226d7b0ef19eaaebe0fed Mon Sep 17 00:00:00 2001 From: larsroettig <l.roettig@techdivision.com> Date: Mon, 5 Nov 2018 00:19:04 +0100 Subject: [PATCH 0467/1158] #18956 Fix for phpunit-test case --- .../Magento/Store/Model/Config/Importer/Processor/Create.php | 4 ++-- .../Test/Unit/Model/Config/Importer/Processor/CreateTest.php | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php index 9d1a7a38ede68..71ffa5303293d 100644 --- a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php +++ b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php @@ -177,8 +177,8 @@ private function createGroups(array $items, array $data) ); $group = $this->groupFactory->create(); - if (!isset($groupData['root_categry_id'])) { - $groupData['root_categry_id'] = 0; + if (!isset($groupData['root_category_id'])) { + $groupData['root_category_id'] = 0; } $group->setData($groupData); diff --git a/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php b/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php index 2c2b0b00aec43..0901464224399 100644 --- a/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php @@ -291,9 +291,6 @@ public function testRunGroup() $this->groupMock->expects($this->exactly(3)) ->method('getResource') ->willReturn($this->abstractDbMock); - $this->groupMock->expects($this->once()) - ->method('setRootCategoryId') - ->with(0); $this->groupMock->expects($this->once()) ->method('getDefaultStoreId') ->willReturn($defaultStoreId); From f9b4595a60d7b81775cdd43f996991acb0d50ff2 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Mon, 5 Nov 2018 12:08:27 +0300 Subject: [PATCH 0468/1158] MAGETWO-91750: Multiselect attribute values is not searchable under Quick Search when more than one value is selected - Fix perfomance --- .../Model/Indexer/Fulltext/Action/DataProvider.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index 421746e7761c1..6cd4e227b85c8 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -653,7 +653,8 @@ private function getAttributeOptionValue($attributeId, $valueIds, $storeId) } } foreach ($attributeValueIds as $attrValueId) { - $attributeOptionValue .= $this->attributeOptions[$optionKey][$attrValueId] . ' '; + if (isset($this->attributeOptions[$optionKey][$attrValueId])) + $attributeOptionValue .= $this->attributeOptions[$optionKey][$attrValueId] . ' '; } return empty($attributeOptionValue) ? null : trim($attributeOptionValue); } From da66589239c95d7739b2c01e27628d178ed9c139 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Mon, 5 Nov 2018 12:32:18 +0300 Subject: [PATCH 0469/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix functional test --- .../Mftf/Section/AdminProductFormGroupedProductsSection.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml index 0739c4e601b62..f5549f26bfd56 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml @@ -11,8 +11,8 @@ <section name="AdminProductFormGroupedProductsSection"> <element name="toggleGroupedProduct" type="button" selector="div[data-index=grouped] .admin__collapsible-title"/> <element name="addProductsToGroup" type="button" selector="button[data-index='grouped_products_button']" timeout="30"/> - <element name="nextActionButton" type="button" selector="//button[@class='action-next']"/> - <element name="previousActionButton" type="button" selector="//button[@class='action-previous']"/> + <element name="nextActionButton" type="button" selector=".admin__field > .admin__field-control > .admin__control-table-pagination > .admin__data-grid-pager > .action-next"/> + <element name="previousActionButton" type="button" selector=".admin__field > .admin__field-control > .admin__control-table-pagination > .admin__data-grid-pager > .action-previous"/> <element name="positionProduct" type="input" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[10]//input[@class='position-widget-input']" parameterized="true"/> <element name="nameProductFromGrid" type="text" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[4]//*[@class='admin__field-control']//span" parameterized="true"/> </section> From 1a703c7054e3efc51cf9eded93602c6d4b93f726 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Mon, 5 Nov 2018 13:11:11 +0300 Subject: [PATCH 0470/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../adminhtml/web/js/grouped-product-grid.js | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index f257cb2df729e..c8e5a58c99e78 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -23,6 +23,7 @@ define([ if (position || position === 0) { this.checkMaxPosition(position); this.sort(position, elem); + if (~~position === this.maxPosition && ~~position > this.getDefaultPageBoundary() + 1) { this.shiftNextPagesPositions(position); } @@ -37,17 +38,17 @@ define([ * @param position */ shiftNextPagesPositions: function (position) { - var recordData = this.recordData(); + + var recordData = this.recordData(), + startIndex = ~~this.currentPage() * this.pageSize, + offset = position - startIndex + 1; if (~~this.currentPage() === this.pages()) { return false; - } else { - var startIndex = ~~this.currentPage() * this.pageSize, - offset = position - startIndex + 1; - for (var index = startIndex; index < recordData.length; index++) { - recordData[index].position = index + offset; - } - this.recordData(recordData); } + for (var index = startIndex; index < recordData.length; index++) { + recordData[index].position = index + offset; + } + this.recordData(recordData); }, @@ -58,14 +59,14 @@ define([ * @param event */ updateGridPosition: function (data, event) { - var inputValue = parseInt(event.target.value), + var inputValue = parseInt(event.target.value, 10), recordData = this.recordData(), record, previousValue, updatedRecord; record = this.elems().find(function (obj) { - return obj.dataScope === data.parentScope + return obj.dataScope === data.parentScope; }); previousValue = this.getCalculatedPosition(record); @@ -105,7 +106,7 @@ define([ */ getUpdatedRecordIndex: function (recordData, recordId) { return recordData.map(function (o) { - return ~~o.id + return ~~o.id; }).indexOf(~~recordId); }, @@ -163,7 +164,7 @@ define([ this.elems([]); updatedRecord = this.getUpdatedRecordIndex(recordData, objectToUpdate.data().id); recordData.forEach(function (value, index) { - recordData[index].position = (index === updatedRecord) ? 0 : value.position + 1; + recordData[index].position = index === updatedRecord ? 0 : value.position + 1; }); this.reloadGridData(recordData); } @@ -198,7 +199,7 @@ define([ * @return {number} */ getDefaultPageBoundary: function () { - return (~~this.currentPage() * this.pageSize) - 1; + return ~~this.currentPage() * this.pageSize - 1; }, /** @@ -208,7 +209,7 @@ define([ */ getGlobalMaxPosition: function () { return _.max(this.recordData().map(function (r) { - return ~~r.position + return ~~r.position; })); } }); From 322d82bc8af1c8fefc3cde25536a82556f59aadc Mon Sep 17 00:00:00 2001 From: David Manners <dmanners87@gmail.com> Date: Mon, 5 Nov 2018 10:51:26 +0000 Subject: [PATCH 0471/1158] magento-engcom/import-export-improvements#122: Update History file for phpstyle check --- app/code/Magento/ImportExport/Model/History.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/ImportExport/Model/History.php b/app/code/Magento/ImportExport/Model/History.php index 617ca11e18f22..19d62259c02a2 100644 --- a/app/code/Magento/ImportExport/Model/History.php +++ b/app/code/Magento/ImportExport/Model/History.php @@ -298,6 +298,8 @@ public function setSummary($summary) } /** + * Load the last inserted item + * * @return $this */ public function loadLastInsertItem() From a089fa137b790ef5be815eee7672baabc00b8755 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Mon, 5 Nov 2018 13:29:39 +0200 Subject: [PATCH 0472/1158] ENGCOM-3283: Feature/import success page improvement #138 Fix functional tests. --- .../ImportExport/Test/Constraint/AssertImportSuccessMessage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php index ca75e3b203f63..a5408426514f2 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php @@ -28,7 +28,7 @@ class AssertImportSuccessMessage extends AbstractConstraint public function processAssert(AdminImportIndex $adminImportIndex) { $validationMessage = $adminImportIndex->getMessagesBlock()->getImportResultMessage(); - \PHPUnit\Framework\Assert::assertEquals( + \PHPUnit\Framework\Assert::assertStringEndsWith( self::SUCCESS_MESSAGE, $validationMessage, 'Wrong validation result is displayed.' From 2f995d13c332dd4a2e560373d231c0f06cf25f98 Mon Sep 17 00:00:00 2001 From: Tobias Maile <tobias.maile@brandung.de> Date: Mon, 5 Nov 2018 12:33:25 +0100 Subject: [PATCH 0473/1158] GraphQL-202: [Mutations] adds description and category_id as parameter --- app/code/Magento/SendFriendGraphQl/etc/schema.graphqls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls b/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls index 87bf90fd10072..4123387650838 100644 --- a/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls +++ b/app/code/Magento/SendFriendGraphQl/etc/schema.graphqls @@ -2,7 +2,7 @@ # See COPYING.txt for license details. type Mutation { - sendEmailToFriend (input: SendEmailToFriendSenderInput): SendEmailToFriendOutput @resolver(class: "\\Magento\\SendFriendGraphQl\\Model\\Resolver\\SendEmailToFriend") @doc(description:"@todo") + sendEmailToFriend (input: SendEmailToFriendSenderInput): SendEmailToFriendOutput @resolver(class: "\\Magento\\SendFriendGraphQl\\Model\\Resolver\\SendEmailToFriend") @doc(description:"Recommends Product by Sending Single/Multiple Email") } input SendEmailToFriendSenderInput { @@ -16,9 +16,9 @@ type Sender { email: String! message: String! } -#@todo Prams can be removed if dispatching of event in app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php not needed type Params { product_id: Int! + category_id: Int! } type Recipient { From 1fb624d381e67581a06e66809883e51a4a4b0d75 Mon Sep 17 00:00:00 2001 From: Tobias Maile <tobias.maile@brandung.de> Date: Mon, 5 Nov 2018 12:34:46 +0100 Subject: [PATCH 0474/1158] GraphQL-202: [Mutations] moves validation logic to separate module --- .../Model/Validation/Validation.php | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 app/code/Magento/SendFriendGraphQl/Model/Validation/Validation.php diff --git a/app/code/Magento/SendFriendGraphQl/Model/Validation/Validation.php b/app/code/Magento/SendFriendGraphQl/Model/Validation/Validation.php new file mode 100644 index 0000000000000..49f7feeaba489 --- /dev/null +++ b/app/code/Magento/SendFriendGraphQl/Model/Validation/Validation.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SendFriendGraphQl\Model\Validation; + +use Magento\Framework\DataObjectFactory; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\SendFriend\Model\SendFriend; + +class Validation +{ + /** + * @var SendFriend + */ + private $sendFriend; + /** + * @var DataObjectFactory + */ + private $dataObjectFactory; + + public function __construct( + DataObjectFactory $dataObjectFactory, + SendFriend $sendFriend + ) { + $this->sendFriend = $sendFriend; + $this->dataObjectFactory = $dataObjectFactory; + } + + /** + * @param $args + * @param array $recipientsArray + * @throws GraphQlInputException + */ + public function validate($args, array $recipientsArray): void + { + $this->prepareDataForSendFriendValidation($args, $recipientsArray); + $validationResult = $this->sendFriend->validate(); + if ($validationResult !== true) { + throw new GraphQlInputException(__(implode($validationResult))); + } + if ($this->sendFriend->getMaxSendsToFriend() && $this->sendFriend->isExceedLimit()) { + throw new GraphQlInputException(__('You can\'t send messages more than %1 times an hour.', + $this->sendFriend->getMaxSendsToFriend() + )); + } + } + + private function prepareDataForSendFriendValidation(array $args, array $recipientsArray): void + { + $sender = $this->dataObjectFactory->create()->setData([ + 'name' => $args['input']['sender']['name'], + 'email'=> $args['input']['sender']['email'], + 'message' => $args['input']['sender']['message'], + ]); + $emails = []; + foreach ($recipientsArray['recipients'] as $recipient) { + $emails[] = $recipient['email']; + } + $recipients = $this->dataObjectFactory->create()->setData('emails', $emails); + + $this->sendFriend->setData('_sender', $sender); + $this->sendFriend->setData('_recipients', $recipients); + } + +} \ No newline at end of file From 2a021c075f52e39b03dc8c30ba418afc57851041 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Mon, 5 Nov 2018 17:12:32 +0300 Subject: [PATCH 0475/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../view/adminhtml/web/js/grouped-product-grid.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index c8e5a58c99e78..3fb7e9ecc8b4b 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -35,17 +35,19 @@ define([ /** * Shift positions for next page elements * - * @param position + * @param {Number} position */ shiftNextPagesPositions: function (position) { var recordData = this.recordData(), startIndex = ~~this.currentPage() * this.pageSize, - offset = position - startIndex + 1; + offset = position - startIndex + 1, + index = startIndex; + if (~~this.currentPage() === this.pages()) { return false; } - for (var index = startIndex; index < recordData.length; index++) { + for (index; index < recordData.length; index++) { recordData[index].position = index + offset; } this.recordData(recordData); From e18bcb5f846df4ae8fd84f2b66890984982aee04 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <veronika_kurochkina@epam.com> Date: Mon, 5 Nov 2018 17:15:28 +0300 Subject: [PATCH 0476/1158] MAGETWO-91750: Multiselect attribute values is not searchable under Quick Search when more than one value is selected - Fix static testd --- .../Model/Indexer/Fulltext/Action/DataProvider.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index 6cd4e227b85c8..39cb95747c2cf 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -653,8 +653,9 @@ private function getAttributeOptionValue($attributeId, $valueIds, $storeId) } } foreach ($attributeValueIds as $attrValueId) { - if (isset($this->attributeOptions[$optionKey][$attrValueId])) + if (isset($this->attributeOptions[$optionKey][$attrValueId])) { $attributeOptionValue .= $this->attributeOptions[$optionKey][$attrValueId] . ' '; + } } return empty($attributeOptionValue) ? null : trim($attributeOptionValue); } From 518b4d4a181ffd60d57909b12b07fd39f149d9c7 Mon Sep 17 00:00:00 2001 From: David Manners <dmanners87@gmail.com> Date: Mon, 5 Nov 2018 14:41:29 +0000 Subject: [PATCH 0477/1158] magento-engcom/import-export-improvements#126: update the download controller to implement the HttpGetActionInterface --- .../ImportExport/Controller/Adminhtml/History/Download.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php b/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php index 4dda5ebc4a310..d46fda9a1c0ef 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php @@ -6,9 +6,10 @@ */ namespace Magento\ImportExport\Controller\Adminhtml\History; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Filesystem\DirectoryList; -class Download extends \Magento\ImportExport\Controller\Adminhtml\History +class Download extends \Magento\ImportExport\Controller\Adminhtml\History implements HttpGetActionInterface { /** * @var \Magento\Framework\Controller\Result\RawFactory From 0f4c7946bc003d05dfa4330ffb4a09cc08206435 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 5 Nov 2018 09:44:42 -0600 Subject: [PATCH 0478/1158] MAGETWO-95212: block call to getCurrentUrl method is returning ajax request value - Removed unintended change --- app/code/Magento/Catalog/Block/Product/AbstractProduct.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php index fb45246ea3464..c8da0f70f73b6 100644 --- a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php +++ b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php @@ -266,7 +266,6 @@ public function getProductUrl($product, $additional = []) if (!isset($additional['_escape'])) { $additional['_escape'] = true; } - $additional['useUencPlaceholder'] = true; return $product->getUrlModel()->getUrl($product, $additional); } From b9367a6bab6272cc4efada12370181aaf19fa9d7 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 5 Nov 2018 10:31:23 -0600 Subject: [PATCH 0479/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Fixed namespace --- .../Magento/GroupedProduct/Api/CartItemRepositoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php index 61f07ac3aa043..602493481449f 100644 --- a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php @@ -4,7 +4,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\GroupedProduce\Api; +namespace Magento\GroupedProduct\Api; use Magento\Catalog\Model\CustomOptions\CustomOptionProcessor; use Magento\Framework\Webapi\Rest\Request; From 3785225428b54e81f0b6a09e0528af0978354044 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Mon, 5 Nov 2018 18:33:04 +0200 Subject: [PATCH 0480/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Static fixes; --- .../adminhtml/web/js/address/default-address.js | 16 ++++++++-------- .../Magento_Customer/web/css/source/_module.less | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index b4ec734cb4033..530df8544c841 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -10,8 +10,8 @@ define([ return Button.extend({ defaults: { - entity_id: null, - parent_id: null + entityId: null, + parentId: null }, /** @@ -21,8 +21,8 @@ define([ */ initialize: function () { this._super(); - if (!this.parent_id) { - this.visible(this.entity_id); + if (!this.parentId) { + this.visible(this.entityId); } return this; @@ -36,12 +36,12 @@ define([ */ applyAction: function (action) { if (action.params && action.params[0]) { - action.params[0].entity_id = this.entity_id; - action.params[0].parent_id = this.parent_id; + action.params[0].entityId = this.entityId; + action.params[0].parentId = this.parentId; } else { action.params = [{ - entity_id: this.entity_id, - parent_id: this.parent_id + entityId: this.entityId, + parentId: this.parentId }]; } diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index 876859ff38d1a..7cb02b61fdbd8 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -16,8 +16,8 @@ .customer-address-form { *, - *:before, - *:after { + *:after, + *:before { box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; From ca90fef1a09a8dc0e03299df89ba7c0e24ea05dc Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Mon, 5 Nov 2018 18:40:22 +0200 Subject: [PATCH 0481/1158] MAGETWO-96024: Invalid element declared for AdminProductGridSection section. Delete empty files --- .../ChangeStatusProductUsingProductGridActionGroup.xml | 0 .../Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml delete mode 100644 app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml diff --git a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml b/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml deleted file mode 100644 index e69de29bb2d1d..0000000000000 From a40eb487b7d3f57d6241620ff2f49d9b4196f383 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Mon, 5 Nov 2018 10:42:57 -0600 Subject: [PATCH 0482/1158] ENGCOM-3355: [Forwardport] Fix Authenticating a customer via REST API does not update the last logged in data #18973 - Fixed docblocks --- app/code/Magento/Integration/Model/CustomerTokenService.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Integration/Model/CustomerTokenService.php b/app/code/Magento/Integration/Model/CustomerTokenService.php index 35d0424d3b4fa..7c2c444a734eb 100644 --- a/app/code/Magento/Integration/Model/CustomerTokenService.php +++ b/app/code/Magento/Integration/Model/CustomerTokenService.php @@ -16,6 +16,9 @@ use Magento\Framework\Exception\AuthenticationException; use Magento\Framework\Event\ManagerInterface; +/** + * @inheritdoc + */ class CustomerTokenService implements \Magento\Integration\Api\CustomerTokenServiceInterface { /** @@ -79,7 +82,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function createCustomerAccessToken($username, $password) { From 577b17576161edc6a3587d4b93a66fcac60f91a7 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Mon, 5 Nov 2018 10:50:32 -0600 Subject: [PATCH 0483/1158] ENGCOM-3354: Cancel expired orders using OrderManagementInterface #18832 - Fixed docblock --- app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php index 80370c21d4d7b..999bb1786cf83 100644 --- a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php +++ b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php @@ -13,6 +13,9 @@ use Magento\Store\Model\StoresConfig; use Magento\Sales\Model\Order; +/** + * Class that provides functionality of cleaning expired quotes by cron + */ class CleanExpiredOrders { /** From 90831f56053bc2af291468e01bead189441eb25c Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Mon, 5 Nov 2018 19:16:24 +0200 Subject: [PATCH 0484/1158] graphQl: removed not needed exception, added test coverage --- .../Model/Cart/SetShippingAddressOnCart.php | 9 +- .../Quote/SetShippingAddressOnCartTest.php | 424 ++++++++++++++++++ 2 files changed, 425 insertions(+), 8 deletions(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php index 43e58bb807672..a2d93ac1753c5 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php @@ -84,19 +84,12 @@ public function setAddresses(ContextInterface $context, int $cartId, array $ship if ((!$context->getUserId()) || $context->getUserType() == UserContextInterface::USER_TYPE_GUEST) { throw new GraphQlAuthorizationException( __( - 'Address management allowed only for authorized customers' + 'Address management allowed only for authorized customers.' ) ); } /** @var AddressInterface $customerAddress */ $customerAddress = $this->addressRepository->getById($customerAddressId); - if ($context->getUserId() !== (int)$customerAddress->getCustomerId()) { - throw new GraphQlInputException( - __( - 'Address is not applicable for current customer' - ) - ); - } $shippingAddress = $this->addressModel->importCustomerAddressData($customerAddress); } else { $shippingAddress = $this->addressModel->addData($addressInput); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php new file mode 100644 index 0000000000000..9771dbbf84c48 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php @@ -0,0 +1,424 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Quote; + +use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface; +use Magento\Quote\Model\ResourceModel\Quote as QuoteResource; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; +use Magento\TestFramework\ObjectManager; + +/** + * Test for set shipping addresses on cart mutation + */ +class SetShippingAddressOnCartTest extends GraphQlAbstract +{ + /** + * @var QuoteResource + */ + private $quoteResource; + + /** + * @var Quote + */ + private $quote; + + /** + * @var QuoteIdToMaskedQuoteIdInterface + */ + private $quoteIdToMaskedId; + + protected function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->quoteResource = $objectManager->create(QuoteResource::class); + $this->quote = $objectManager->create(Quote::class); + $this->quoteIdToMaskedId = $objectManager->create(QuoteIdToMaskedQuoteIdInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testSetNewGuestShippingAddressOnCart() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "test city" + region: "test region" + postcode: "887766" + country_code: "US" + telephone: "88776655" + save_in_address_book: false + } + } + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + + self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $cartResponse = $response['setShippingAddressesOnCart']['cart']; + self::assertArrayHasKey('addresses', $cartResponse); + $shippingAddressResponse = current($cartResponse['addresses']); + $this->assertNewShippingAddressFields($shippingAddressResponse); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testSetSavedShippingAddressOnCartByGuest() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + customer_address_id: 1 + } + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + self::expectExceptionMessage('Address management allowed only for authorized customers.'); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testSetSavedAndNewShippingAddressOnCartAtTheSameTime() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + customer_address_id: 1, + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "test city" + region: "test region" + postcode: "887766" + country_code: "US" + telephone: "88776655" + save_in_address_book: false + } + } + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + self::expectExceptionMessage( + 'Shipping address can\'t contain "customer_address_id" and "address" input at the same time.' + ); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testSetShippingAddressOnCartWithNoAddresses() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + {} + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + self::expectExceptionMessage( + 'Shipping address should contain either "customer_address_id" or "address" input.' + ); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testSetNewRegisteredCustomerShippingAddressOnCart() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $this->quote->setCustomerId(1); + $this->quoteResource->save($this->quote); + + $headerMap = $this->getHeaderMap(); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "test city" + region: "test region" + postcode: "887766" + country_code: "US" + telephone: "88776655" + save_in_address_book: false + } + } + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query, [], '', $headerMap); + + self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $cartResponse = $response['setShippingAddressesOnCart']['cart']; + self::assertArrayHasKey('addresses', $cartResponse); + $shippingAddressResponse = current($cartResponse['addresses']); + $this->assertNewShippingAddressFields($shippingAddressResponse); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php + */ + public function testSetSavedRegisteredCustomerShippingAddressOnCart() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $this->quote->setCustomerId(1); + $this->quoteResource->save($this->quote); + + $headerMap = $this->getHeaderMap(); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + customer_address_id: 1 + } + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query, [], '', $headerMap); + + self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $cartResponse = $response['setShippingAddressesOnCart']['cart']; + self::assertArrayHasKey('addresses', $cartResponse); + $shippingAddressResponse = current($cartResponse['addresses']); + $this->assertSavedShippingAddressFields($shippingAddressResponse); + } + + /** + * Verify the all the whitelisted fields for a New Address Object + * + * @param array $shippingAddressResponse + */ + private function assertNewShippingAddressFields(array $shippingAddressResponse): void + { + $assertionMap = [ + ['response_field' => 'firstname', 'expected_value' => 'test firstname'], + ['response_field' => 'lastname', 'expected_value' => 'test lastname'], + ['response_field' => 'company', 'expected_value' => 'test company'], + ['response_field' => 'street', 'expected_value' => [0 => 'test street 1', 1 => 'test street 2']], + ['response_field' => 'city', 'expected_value' => 'test city'], + ['response_field' => 'postcode', 'expected_value' => '887766'], + ['response_field' => 'telephone', 'expected_value' => '88776655'] + ]; + + $this->assertResponseFields($shippingAddressResponse, $assertionMap); + } + + /** + * Verify the all the whitelisted fields for a Address Object + * + * @param array $shippingAddressResponse + */ + private function assertSavedShippingAddressFields(array $shippingAddressResponse): void + { + $assertionMap = [ + ['response_field' => 'firstname', 'expected_value' => 'John'], + ['response_field' => 'lastname', 'expected_value' => 'Smith'], + ['response_field' => 'company', 'expected_value' => 'CompanyName'], + ['response_field' => 'street', 'expected_value' => [0 => 'Green str, 67']], + ['response_field' => 'city', 'expected_value' => 'CityM'], + ['response_field' => 'postcode', 'expected_value' => '75477'], + ['response_field' => 'telephone', 'expected_value' => '3468676'] + ]; + + $this->assertResponseFields($shippingAddressResponse, $assertionMap); + } + + /** + * @param string $username + * @return array + */ + private function getHeaderMap(string $username = 'customer@example.com'): array + { + $password = 'password'; + /** @var CustomerTokenServiceInterface $customerTokenService */ + $customerTokenService = ObjectManager::getInstance() + ->get(CustomerTokenServiceInterface::class); + $customerToken = $customerTokenService->createCustomerAccessToken($username, $password); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + return $headerMap; + } +} From 5d2b1c8d80f23a8061c63702d370728d05234cd5 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Mon, 5 Nov 2018 19:17:53 +0200 Subject: [PATCH 0485/1158] graphQl: fixed dependency issue --- app/code/Magento/QuoteGraphQl/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index c9900dd5f3150..485c958718bf3 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -7,7 +7,8 @@ "magento/framework": "*", "magento/module-quote": "*", "magento/module-catalog": "*", - "magento/module-store": "*" + "magento/module-store": "*", + "magento/module-checkout": "*" }, "suggest": { "magento/module-graph-ql": "*" From 743d3ebd5584b61b3c3d1ff804767871caff470c Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Mon, 5 Nov 2018 11:46:52 -0600 Subject: [PATCH 0486/1158] MAGETWO-95248: Show Packages button in Shipping and Tracking information section of Shipments doesn't work --- .../view/adminhtml/web/js/packages.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 app/code/Magento/Shipping/view/adminhtml/web/js/packages.js diff --git a/app/code/Magento/Shipping/view/adminhtml/web/js/packages.js b/app/code/Magento/Shipping/view/adminhtml/web/js/packages.js new file mode 100644 index 0000000000000..f46ad4192d170 --- /dev/null +++ b/app/code/Magento/Shipping/view/adminhtml/web/js/packages.js @@ -0,0 +1,39 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'Magento_Ui/js/modal/modal', + 'mage/translate' +], function ($, modal, $t) { + 'use strict'; + + return function (config, element) { + config.buttons = [ + { + text: $t('Print'), + 'class': 'action action-primary', + + /** + * Click handler + */ + click: function () { + window.location.href = this.options.url; + } + }, { + text: $t('Cancel'), + 'class': 'action action-secondary', + + /** + * Click handler + */ + click: function () { + this.closeModal(); + } + } + ]; + modal(config, element); + }; +}); From 3343ad61aa8ac0d596f5b6783b25852d8589f966 Mon Sep 17 00:00:00 2001 From: Dmytro Drozd <ddrozd@magento.com> Date: Mon, 5 Nov 2018 20:41:11 +0200 Subject: [PATCH 0487/1158] MAGETWO-96026: Create MFTF test for MAGETWO-93973. Add more stability --- ...PricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml index 6eb78809b187d..a8b2df1fcfa67 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/TieredPricingAndQuantityIncrementsWorkWithDecimalinventoryTest.xml @@ -63,7 +63,9 @@ <click selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrementsUseConfigSettings}}" stepKey="clickOnEnableQtyIncrementsUseConfigSettingsCheckbox"/> <click selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrements}}" stepKey="clickOnEnableQtyIncrements"/> <click selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrementsOptions(('1'))}}" stepKey="chooseYesOnEnableQtyIncrements"/> + <scrollTo selector="{{AdminProductFormAdvancedInventorySection.qtyIncrementsUseConfigSettings}}" stepKey="scrollToQtyIncrementsUseConfigSettings"/> <click selector="{{AdminProductFormAdvancedInventorySection.qtyIncrementsUseConfigSettings}}" stepKey="clickOnQtyIncrementsUseConfigSettings"/> + <scrollTo selector="{{AdminProductFormAdvancedInventorySection.qtyIncrements}}" stepKey="scrollToQtyIncrements"/> <fillField selector="{{AdminProductFormAdvancedInventorySection.qtyIncrements}}" userInput=".5" stepKey="fillQtyIncrements"/> <!--Step6. Close *Advanced Inventory* (Click on button *Done*). Save *prod1* (Click on button *Save*) --> <click selector="{{AdminProductFormAdvancedInventorySection.doneButton}}" stepKey="clickOnDoneButton3"/> From e1f09fb984df705e35dde07092d04957c7c0e5c1 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Mon, 5 Nov 2018 21:15:25 +0200 Subject: [PATCH 0488/1158] graphQl: added extension point for multishipping --- .../Model/Cart/SetShippingAddressesOnCart.php | 48 +++++++++++++++++++ .../SingleShippingAddressProcessor.php} | 20 +++----- .../SetShippingAddressesOnCartInterface.php | 31 ++++++++++++ .../Resolver/SetShippingAddressesOnCart.php | 22 ++++----- .../Magento/QuoteGraphQl/etc/graphql/di.xml | 9 ++++ 5 files changed, 106 insertions(+), 24 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php rename app/code/Magento/QuoteGraphQl/Model/Cart/{SetShippingAddressOnCart.php => SetShippingAddressesOnCart/SingleShippingAddressProcessor.php} (85%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php new file mode 100644 index 0000000000000..ad3615b94f8ef --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Cart; + +use InvalidArgumentException; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; + +/** + * Set shipping addresses for shopping cart processors chain + */ +class SetShippingAddressesOnCart implements SetShippingAddressesOnCartInterface +{ + /** + * @var SetShippingAddressesOnCartInterface[] + */ + private $shippingAddressProcessors; + + /** + * @param array $shippingAddressProcessors + */ + public function __construct( + array $shippingAddressProcessors + ) { + $this->shippingAddressProcessors = $shippingAddressProcessors; + } + + /** + * @inheritdoc + */ + public function execute(ContextInterface $context, int $cartId, array $shippingAddresses): void + { + foreach ($this->shippingAddressProcessors as $shippingAddressProcessor) { + if (!$shippingAddressProcessor instanceof SetShippingAddressesOnCartInterface) { + throw new InvalidArgumentException( + get_class($shippingAddressProcessor) . + ' is not instance of \Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface.' + ); + } + + $shippingAddressProcessor->execute($context, $cartId, $shippingAddresses); + } + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php similarity index 85% rename from app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php rename to app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php index a2d93ac1753c5..6584b9887bed5 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Cart; +namespace Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCart; use Magento\Authorization\Model\UserContextInterface; use Magento\Customer\Api\Data\AddressInterface; @@ -15,13 +15,12 @@ use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\ShippingAddressManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface; /** - * Class SetShippingAddressOnCart - * - * Set shipping address for a specified shopping cart + * Set single shipping address for a specified shopping cart */ -class SetShippingAddressOnCart +class SingleShippingAddressProcessor implements SetShippingAddressesOnCartInterface { /** * @var ShippingAddressManagementInterface @@ -54,17 +53,12 @@ public function __construct( } /** - * @param ContextInterface $context - * @param int $cartId - * @param array $shippingAddresses - * @return void + * @inheritdoc */ - public function setAddresses(ContextInterface $context, int $cartId, array $shippingAddresses): void + public function execute(ContextInterface $context, int $cartId, array $shippingAddresses): void { if (count($shippingAddresses) > 1) { - throw new GraphQlInputException( - __('Multiple address does not allowed here!') - ); + return; } $shippingAddress = current($shippingAddresses); $customerAddressId = $shippingAddress['customer_address_id'] ?? null; diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php new file mode 100644 index 0000000000000..f9623e36c5395 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Cart; + +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; + +/** + * Extension point for setting shipping addresses for a specified shopping cart + * + * All objects that are responsible for set shipping addresses on cart via GraphQl should implement this interface. + */ +interface SetShippingAddressesOnCartInterface +{ + + /** + * Set shipping addresses for a specified shopping cart + * + * @param ContextInterface $context + * @param int $cartId + * @param array $shippingAddresses + * @return void + * @throws GraphQlInputException + */ + public function execute(ContextInterface $context, int $cartId, array $shippingAddresses): void; +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php index fcb4255a75eb7..ec151214dbc42 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php @@ -15,7 +15,7 @@ use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Quote\Model\ShippingAddressManagementInterface; use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; -use Magento\QuoteGraphQl\Model\Cart\SetShippingAddressOnCart; +use Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface; /** * Class SetShippingAddressesOnCart @@ -29,11 +29,6 @@ class SetShippingAddressesOnCart implements ResolverInterface */ private $maskedQuoteIdToQuoteId; - /** - * @var SetShippingAddressOnCart - */ - private $setShippingAddressOnCart; - /** * @var ShippingAddressManagementInterface */ @@ -49,25 +44,30 @@ class SetShippingAddressesOnCart implements ResolverInterface */ private $arrayManager; + /** + * @var SetShippingAddressesOnCartInterface + */ + private $setShippingAddressesOnCart; + /** * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId - * @param SetShippingAddressOnCart $setShippingAddressOnCart * @param ShippingAddressManagementInterface $shippingAddressManagement * @param GetCartForUser $getCartForUser * @param ArrayManager $arrayManager + * @param SetShippingAddressesOnCartInterface $setShippingAddressesOnCart */ public function __construct( MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - SetShippingAddressOnCart $setShippingAddressOnCart, ShippingAddressManagementInterface $shippingAddressManagement, GetCartForUser $getCartForUser, - ArrayManager $arrayManager + ArrayManager $arrayManager, + SetShippingAddressesOnCartInterface $setShippingAddressesOnCart ) { $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->setShippingAddressOnCart = $setShippingAddressOnCart; $this->shippingAddressManagement = $shippingAddressManagement; $this->getCartForUser = $getCartForUser; $this->arrayManager = $arrayManager; + $this->setShippingAddressesOnCart = $setShippingAddressesOnCart; } /** @@ -89,7 +89,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $cart = $this->getCartForUser->execute($maskedCartId, $context->getUserId()); $cartId = (int)$cart->getEntityId(); - $this->setShippingAddressOnCart->setAddresses($context, $cartId, $shippingAddresses); + $this->setShippingAddressesOnCart->execute($context, $cartId, $shippingAddresses); return [ 'cart' => [ diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml index 43941c9740048..f28d484fa0f6f 100644 --- a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml @@ -6,6 +6,15 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <preference for="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface" + type="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCart" /> + <type name="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface"> + <arguments> + <argument name="shippingAddressProcessors" xsi:type="array"> + <item name="singleShippingAddress" xsi:type="object">Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCart\SingleShippingAddressProcessor</item> + </argument> + </arguments> + </type> <virtualType name="multishippingPaymentSpecification" type="Magento\Payment\Model\Method\Specification\Composite"> <arguments> <argument name="specifications" xsi:type="array"> From 55b6f4e46809d162e2258e4da760228ec4062a93 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Mon, 5 Nov 2018 22:12:55 +0200 Subject: [PATCH 0489/1158] graphQl: fixed SetShippingAddressesInterface param --- .../QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php | 5 +++-- .../SingleShippingAddressProcessor.php | 5 +++-- .../Model/Cart/SetShippingAddressesOnCartInterface.php | 5 +++-- .../Model/Resolver/SetShippingAddressesOnCart.php | 3 +-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php index ad3615b94f8ef..8ebcdef1f549a 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php @@ -9,6 +9,7 @@ use InvalidArgumentException; use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Quote\Api\Data\CartInterface; /** * Set shipping addresses for shopping cart processors chain @@ -32,7 +33,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(ContextInterface $context, int $cartId, array $shippingAddresses): void + public function execute(ContextInterface $context, CartInterface $cart, array $shippingAddresses): void { foreach ($this->shippingAddressProcessors as $shippingAddressProcessor) { if (!$shippingAddressProcessor instanceof SetShippingAddressesOnCartInterface) { @@ -42,7 +43,7 @@ public function execute(ContextInterface $context, int $cartId, array $shippingA ); } - $shippingAddressProcessor->execute($context, $cartId, $shippingAddresses); + $shippingAddressProcessor->execute($context, $cart, $shippingAddresses); } } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php index 6584b9887bed5..41675716c68bf 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php @@ -12,6 +12,7 @@ use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\ShippingAddressManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; @@ -55,7 +56,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(ContextInterface $context, int $cartId, array $shippingAddresses): void + public function execute(ContextInterface $context, CartInterface $cart, array $shippingAddresses): void { if (count($shippingAddresses) > 1) { return; @@ -89,6 +90,6 @@ public function execute(ContextInterface $context, int $cartId, array $shippingA $shippingAddress = $this->addressModel->addData($addressInput); } - $this->shippingAddressManagement->assign($cartId, $shippingAddress); + $this->shippingAddressManagement->assign($cart->getId(), $shippingAddress); } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php index f9623e36c5395..ae337240c3a26 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php @@ -9,6 +9,7 @@ use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; +use Magento\Quote\Api\Data\CartInterface; /** * Extension point for setting shipping addresses for a specified shopping cart @@ -22,10 +23,10 @@ interface SetShippingAddressesOnCartInterface * Set shipping addresses for a specified shopping cart * * @param ContextInterface $context - * @param int $cartId + * @param CartInterface $cart * @param array $shippingAddresses * @return void * @throws GraphQlInputException */ - public function execute(ContextInterface $context, int $cartId, array $shippingAddresses): void; + public function execute(ContextInterface $context, CartInterface $cart, array $shippingAddresses): void; } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php index ec151214dbc42..587ebb2b6db1f 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetShippingAddressesOnCart.php @@ -87,9 +87,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $maskedCartId = $args['input']['cart_id']; $cart = $this->getCartForUser->execute($maskedCartId, $context->getUserId()); - $cartId = (int)$cart->getEntityId(); - $this->setShippingAddressesOnCart->execute($context, $cartId, $shippingAddresses); + $this->setShippingAddressesOnCart->execute($context, $cart, $shippingAddresses); return [ 'cart' => [ From e496e26af5dfbe6d109a48c7f0071cd257bcf7fc Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Mon, 5 Nov 2018 14:32:34 -0600 Subject: [PATCH 0490/1158] MAGETWO-95589: [FT][Temando] Tests fail with enabled Temando extension --- .../Mftf/ActionGroup/StorefrontProductCartActionGroup.xml | 5 ++++- .../Test/Mftf/Section/CheckoutCartSummarySection.xml | 1 + .../Test/Mftf/Test/StorefrontCartPriceRuleCountry.xml | 3 ++- .../Test/Mftf/Test/StorefrontCartPriceRulePostcode.xml | 3 ++- .../Test/Mftf/Test/StorefrontCartPriceRuleState.xml | 3 ++- .../CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml | 2 ++ .../Test/Block/Adminhtml/Order/Create/Shipping/Method.php | 1 - 7 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml index 4b5b250078ad4..8ef9ff9e8df38 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml @@ -84,7 +84,10 @@ <argument name="total"/> </arguments> <seeInCurrentUrl url="{{CheckoutCartPage.url}}" stepKey="assertUrl"/> - <waitForText userInput="${{total}}" selector="{{CheckoutCartSummarySection.total}}" time="30" stepKey="waitForTotal"/> + <waitForPageLoad stepKey="waitForCartPage"/> + <conditionalClick selector="{{CheckoutCartSummarySection.shippingHeading}}" dependentSelector="{{CheckoutCartSummarySection.shippingMethodForm}}" visible="false" stepKey="openEstimateShippingSection"/> + <waitForElementVisible selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="waitForShippingSection"/> + <checkOption selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectShippingMethod"/> <see userInput="${{subtotal}}" selector="{{CheckoutCartSummarySection.subtotal}}" stepKey="assertSubtotal"/> <see userInput="${{shipping}}" selector="{{CheckoutCartSummarySection.shipping}}" stepKey="assertShipping"/> <see userInput="({{shippingMethod}})" selector="{{CheckoutCartSummarySection.shippingMethod}}" stepKey="assertShippingMethod"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml index a1a8d2ba3eade..c2e0868848188 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="CheckoutCartSummarySection"> <element name="subtotal" type="text" selector="//*[@id='cart-totals']//tr[@class='totals sub']//td//span[@class='price']"/> + <element name="shippingMethodForm" type="text" selector="#co-shipping-method-form"/> <element name="shippingMethod" type="text" selector="//*[@id='cart-totals']//tr[@class='totals shipping excl']//th//span[@class='value']"/> <element name="shipping" type="text" selector="//*[@id='cart-totals']//tr[@class='totals shipping excl']//td//span[@class='price']"/> <element name="total" type="text" selector="//*[@id='cart-totals']//tr[@class='grand totals']//td//span[@class='price']"/> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountry.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountry.xml index 3eec020e26347..045fdbb33763f 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountry.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountry.xml @@ -72,11 +72,12 @@ <!-- Should not see the discount yet because we have not set country --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCartPage"/> <waitForPageLoad stepKey="waitForCartPage"/> + <click selector="{{CheckoutCartSummarySection.shippingHeading}}" stepKey="openEstimateShippingSection"/> + <checkOption selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectFlatRateShipping"/> <see selector="{{CheckoutCartSummarySection.subtotal}}" userInput="$123.00" stepKey="seeSubtotal"/> <dontSeeElement selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="dontSeeDiscount"/> <!-- See discount if we use valid country --> - <click selector="{{CheckoutCartSummarySection.shippingHeading}}" stepKey="expandShipping"/> <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="Brazil" stepKey="fillCountry"/> <waitForPageLoad stepKey="waitForCountry1"/> <waitForElementVisible selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="waitForDiscountElement"/> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcode.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcode.xml index 73b5d2546f439..d8c3ef9c32b0b 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcode.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcode.xml @@ -76,11 +76,12 @@ <!-- Should not see the discount yet because we have not filled in postcode --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCartPage"/> <waitForPageLoad stepKey="waitForCartPage"/> + <click selector="{{CheckoutCartSummarySection.shippingHeading}}" stepKey="openEstimateShippingSection"/> + <checkOption selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectFlatRateShipping"/> <see selector="{{CheckoutCartSummarySection.subtotal}}" userInput="$123.00" stepKey="seeSubtotal"/> <dontSeeElement selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="dontSeeDiscount"/> <!-- See discount if we use valid postcode --> - <click selector="{{CheckoutCartSummarySection.shippingHeading}}" stepKey="expandShipping"/> <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="78613" stepKey="fillPostcode"/> <waitForPageLoad stepKey="waitForPostcode1"/> <waitForElementVisible selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="waitForDiscountElement"/> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleState.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleState.xml index 9395e87c20edb..647f4d6e5c800 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleState.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleState.xml @@ -72,11 +72,12 @@ <!-- Should not see the discount yet because we have not filled in postcode --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCartPage"/> <waitForPageLoad stepKey="waitForCartPage"/> + <click selector="{{CheckoutCartSummarySection.shippingHeading}}" stepKey="expandShipping"/> + <checkOption selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectFlatRateShipping"/> <see selector="{{CheckoutCartSummarySection.subtotal}}" userInput="$123.00" stepKey="seeSubtotal"/> <dontSeeElement selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="dontSeeDiscount"/> <!-- See discount if we use valid postcode --> - <click selector="{{CheckoutCartSummarySection.shippingHeading}}" stepKey="expandShipping"/> <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="Indiana" stepKey="fillState"/> <waitForPageLoad stepKey="waitForPostcode1"/> <waitForElementVisible selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="waitForDiscountElement"/> diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml index 1fad2f282fa5d..719e9bb95694e 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml @@ -106,6 +106,8 @@ <data name="productPrice/0/special" xsi:type="string">5</data> <data name="productPrice/0/sub_total" xsi:type="string">5</data> <data name="productPrice/0/regular" xsi:type="string">10</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleNotAppliedCatalogPage" /> <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleNotAppliedProductPage" /> <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleNotAppliedShoppingCart" /> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php index 2ee6269c39d47..a0520e1c7ef8f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php @@ -67,7 +67,6 @@ function () { */ private function waitFormLoading() { - $this->_rootElement->click(); $this->browser->waitUntil( function () { return $this->browser->find($this->waitElement)->isVisible() ? null : true; From 091a065cddb39c0f8f4d6a324e3aaa7dcad20c8c Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 5 Nov 2018 16:19:47 -0600 Subject: [PATCH 0491/1158] MAGETWO-95212: block call to getCurrentUrl method is returning ajax request value - Static fix --- app/code/Magento/CatalogWidget/Block/Product/ProductsList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index 6f1e22593452a..851f9e3fc5e94 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -435,7 +435,7 @@ public function getAddToCartUrl($product, $additional = []) return parent::getAddToCartUrl($product, $additional); } - /* + /** * Get widget block name * * @return string From 8df9f0208f93993a065ace2ee5e32612134898bb Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Tue, 6 Nov 2018 09:30:41 +0200 Subject: [PATCH 0492/1158] MAGETWO-96007: Customer address issue when creating or updating via API --- .../ResourceModel/CustomerRepositoryTest.php | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php index 15afc87405ffd..75dfcf7e8f2fd 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php @@ -294,8 +294,6 @@ public function testUpdateCustomerPreserveAllAddresses() $customerId = 1; $customer = $this->customerRepository->getById($customerId); $customerDetails = $customer->__toArray(); - $defaultBilling = $customerDetails['default_billing']; - $defaultShipping = $customerDetails['default_shipping']; $newCustomerEntity = $this->customerFactory->create(); $this->dataObjectHelper->populateWithArray( $newCustomerEntity, @@ -307,19 +305,8 @@ public function testUpdateCustomerPreserveAllAddresses() $this->customerRepository->save($newCustomerEntity); $newCustomerDetails = $this->customerRepository->getById($customerId); - $newCustomerArray = $newCustomerDetails->__toArray(); //Verify that old addresses are still present $this->assertEquals(2, count($newCustomerDetails->getAddresses())); - $this->assertEquals( - $defaultBilling, - $newCustomerArray['default_billing'], - "Default billing invalid value" - ); - $this->assertEquals( - $defaultShipping, - $newCustomerArray['default_shipping'], - "Default shipping invalid value" - ); } /** @@ -345,19 +332,51 @@ public function testUpdateCustomerDeleteAllAddressesWithEmptyArray() $this->customerRepository->save($newCustomerEntity); $newCustomerDetails = $this->customerRepository->getById($customerId); - $newCustomerArray = $newCustomerDetails->__toArray(); //Verify that old addresses are removed $this->assertEquals(0, count($newCustomerDetails->getAddresses())); - $this->assertEquals( - $newCustomerArray['default_billing'], - null, - "Default billing invalid value" + } + + /** + * Test customer update with new address + * + * @magentoAppArea frontend + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php + */ + public function testUpdateCustomerWithNewAddress() + { + $customerId = 1; + $customer = $this->customerRepository->getById($customerId); + $customerDetails = $customer->__toArray(); + unset($customerDetails['default_billing']); + unset($customerDetails['default_shipping']); + + $beforeSaveCustomer = $this->customerFactory->create(); + $this->dataObjectHelper->populateWithArray( + $beforeSaveCustomer, + $customerDetails, + CustomerInterface::class ); - $this->assertEquals( - $newCustomerArray['default_shipping'], - null, - "Default shipping invalid value" + + $addresses = $customer->getAddresses(); + $beforeSaveAddress = $addresses[0]->__toArray(); + unset($beforeSaveAddress['id']); + $newAddressDataObject = $this->addressFactory->create(); + $this->dataObjectHelper->populateWithArray( + $newAddressDataObject, + $beforeSaveAddress, + AddressInterface::class ); + + $beforeSaveCustomer->setAddresses([$newAddressDataObject]); + $this->customerRepository->save($beforeSaveCustomer); + + $newCustomer = $this->customerRepository->getById($customerId); + $newCustomerAddresses = $newCustomer->getAddresses(); + $addressId = $newCustomerAddresses[0]->getId(); + + $this->assertEquals($newCustomer->getDefaultBilling(), $addressId, "Default billing invalid value"); + $this->assertEquals($newCustomer->getDefaultShipping(), $addressId, "Default shipping invalid value"); } /** From 39055807e508b33d658f18e77caec732b9aaca2b Mon Sep 17 00:00:00 2001 From: Giel Berkers <giel.berkers@isaac.nl> Date: Tue, 6 Nov 2018 09:53:55 +0100 Subject: [PATCH 0493/1158] [BUGFIX] Forward-port of #14861 for Magento 2.3 --- .../ResourceModel/Product/CategoryLink.php | 12 ++- .../Product/CategoryLinkTest.php | 98 ++++++++++++++++++- 2 files changed, 101 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php index b54c19a111508..d4c8ada22529f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php @@ -115,10 +115,14 @@ private function processCategoryLinks($newCategoryPositions, &$oldCategoryPositi { $result = ['changed' => [], 'updated' => []]; foreach ($newCategoryPositions as $newCategoryPosition) { - $key = array_search( - $newCategoryPosition['category_id'], - array_column($oldCategoryPositions, 'category_id') - ); + $key = false; + + foreach ($oldCategoryPositions as $oldKey => $oldCategoryPosition) { + if ((int)$oldCategoryPosition['category_id'] === (int)$newCategoryPosition['category_id']) { + $key = $oldKey; + break; + } + } if ($key === false) { $result['changed'][] = $newCategoryPosition; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php index 9e2b196602993..c0c061ab8a704 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product; use Magento\Catalog\Model\ResourceModel\Product\CategoryLink; @@ -129,9 +130,65 @@ public function testSaveCategoryLinks($newCategoryLinks, $dbCategoryLinks, $affe ); } + $expectedResult = []; + + foreach ($affectedIds as $type => $ids) { + $expectedResult = array_merge($expectedResult, $ids); + + // Verify if the correct insert, update and/or delete actions are performed: + switch ($type) { + case 'insert': + $this->connectionMock + ->expects($this->exactly(empty($ids) ? 0 : 1)) + ->method('insertArray') + ->with( + $this->anything(), + $this->anything(), + $this->callback(function ($data) use ($ids) { + $foundIds = []; + foreach ($data as $row) { + $foundIds[] = $row['category_id']; + } + return $ids === $foundIds; + }) + ); + break; + case 'update': + $this->connectionMock + ->expects($this->exactly(empty($ids) ? 0 : 1)) + ->method('insertOnDuplicate') + ->with( + $this->anything(), + $this->callback(function ($data) use ($ids) { + $foundIds = []; + foreach ($data as $row) { + $foundIds[] = $row['category_id']; + } + return $ids === $foundIds; + }) + ); + break; + case 'delete': + $this->connectionMock + ->expects($this->exactly(empty($ids) ? 0 : 1)) + ->method('delete') + // Verify that the correct category ID's are touched: + ->with( + $this->anything(), + $this->callback(function ($data) use ($ids) { + return array_values($data)[1] === $ids; + }) + ); + break; + } + } + $actualResult = $this->model->saveCategoryLinks($product, $newCategoryLinks); + sort($actualResult); - $this->assertEquals($affectedIds, $actualResult); + sort($expectedResult); + + $this->assertEquals($expectedResult, $actualResult); } /** @@ -151,7 +208,11 @@ public function getCategoryLinksDataProvider() ['category_id' => 3, 'position' => 10], ['category_id' => 4, 'position' => 20], ], - [], // Nothing to update - data not changed + [ + 'update' => [], + 'insert' => [], + 'delete' => [], + ], ], [ [ @@ -162,7 +223,11 @@ public function getCategoryLinksDataProvider() ['category_id' => 3, 'position' => 10], ['category_id' => 4, 'position' => 20], ], - [3, 4, 5], // 4 - updated position, 5 - added, 3 - deleted + [ + 'update' => [4], + 'insert' => [5], + 'delete' => [3], + ], ], [ [ @@ -173,7 +238,11 @@ public function getCategoryLinksDataProvider() ['category_id' => 3, 'position' => 10], ['category_id' => 4, 'position' => 20], ], - [3, 4], // 3 - updated position, 4 - deleted + [ + 'update' => [3], + 'insert' => [], + 'delete' => [4], + ], ], [ [], @@ -181,8 +250,27 @@ public function getCategoryLinksDataProvider() ['category_id' => 3, 'position' => 10], ['category_id' => 4, 'position' => 20], ], - [3, 4], // 3, 4 - deleted + [ + 'update' => [], + 'insert' => [], + 'delete' => [3, 4], + ], ], + [ + [ + ['category_id' => 3, 'position' => 10], + ['category_id' => 4, 'position' => 20], + ], + [ + ['category_id' => 3, 'position' => 20], // swapped positions + ['category_id' => 4, 'position' => 10], // swapped positions + ], + [ + 'update' => [3, 4], + 'insert' => [], + 'delete' => [], + ], + ] ]; } } From 965f838c0e993c8a588f22cc5edc2db55f936a44 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Tue, 6 Nov 2018 11:45:36 +0200 Subject: [PATCH 0494/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Ability to save addresses through CustomerRepository rolled back - Integration tests fixes --- .../ResourceModel/CustomerRepository.php | 57 +++- .../Customer/etc/db_schema_whitelist.json | 3 +- .../ui_component/customer_address_listing.xml | 29 +- .../view/base/ui_component/customer_form.xml | 9 +- .../Controller/Adminhtml/Address/SaveTest.php | 36 ++- .../Controller/Adminhtml/IndexTest.php | 275 +----------------- 6 files changed, 106 insertions(+), 303 deletions(-) diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 5d88cd92c1730..16c650be15b61 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -170,18 +170,22 @@ public function save(CustomerInterface $customer, $passwordHash = null) /** @var NewOperation|null $delegatedNewOperation */ $delegatedNewOperation = !$customer->getId() ? $this->delegatedStorage->consumeNewOperation() : null; $prevCustomerData = null; + $prevCustomerDataArr = null; if ($customer->getId()) { $prevCustomerData = $this->getById($customer->getId()); + $prevCustomerDataArr = $prevCustomerData->__toArray(); } - + /** @var $customer \Magento\Customer\Model\Data\Customer */ + $customerArr = $customer->__toArray(); $customer = $this->imageProcessor->save( $customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $prevCustomerData ); - - /** @var array $customerData */ + $origAddresses = $customer->getAddresses(); + $customer->setAddresses([]); $customerData = $this->extensibleDataObjectConverter->toNestedArray($customer, [], CustomerInterface::class); + $customer->setAddresses($origAddresses); /** @var Customer $customerModel */ $customerModel = $this->customerFactory->create(['data' => $customerData]); //Model's actual ID field maybe different than "id" so "id" field from $customerData may be ignored. @@ -190,16 +194,61 @@ public function save(CustomerInterface $customer, $passwordHash = null) if ($storeId === null) { $customerModel->setStoreId($this->storeManager->getStore()->getId()); } + // Need to use attribute set or future updates can cause data loss + if (!$customerModel->getAttributeSetId()) { + $customerModel->setAttributeSetId(CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER); + } $this->populateCustomerWithSecureData($customerModel, $passwordHash); // If customer email was changed, reset RpToken info if ($prevCustomerData && $prevCustomerData->getEmail() !== $customerModel->getEmail()) { $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } + if (!array_key_exists('default_billing', $customerArr) + && null !== $prevCustomerDataArr + && array_key_exists('default_billing', $prevCustomerDataArr) + ) { + $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); + } + if (!array_key_exists('default_shipping', $customerArr) + && null !== $prevCustomerDataArr + && array_key_exists('default_shipping', $prevCustomerDataArr) + ) { + $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); + } $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); - + if (!$customer->getAddresses() + && $delegatedNewOperation + && $delegatedNewOperation->getCustomer()->getAddresses() + ) { + $customer->setAddresses($delegatedNewOperation->getCustomer()->getAddresses()); + } + if ($customer->getAddresses() !== null) { + if ($customer->getId()) { + $existingAddresses = $this->getById($customer->getId())->getAddresses(); + $getIdFunc = function ($address) { + return $address->getId(); + }; + $existingAddressIds = array_map($getIdFunc, $existingAddresses); + } else { + $existingAddressIds = []; + } + $savedAddressIds = []; + foreach ($customer->getAddresses() as $address) { + $address->setCustomerId($customerId) + ->setRegion($address->getRegion()); + $this->addressRepository->save($address); + if ($address->getId()) { + $savedAddressIds[] = $address->getId(); + } + } + $addressIdsToDelete = array_diff($existingAddressIds, $savedAddressIds); + foreach ($addressIdsToDelete as $addressId) { + $this->addressRepository->deleteById($addressId); + } + } $this->customerRegistry->remove($customerId); $savedCustomer = $this->get($customer->getEmail(), $customer->getWebsiteId()); $this->eventManager->dispatch( diff --git a/app/code/Magento/Customer/etc/db_schema_whitelist.json b/app/code/Magento/Customer/etc/db_schema_whitelist.json index 4aada8f0d81fe..ec7a53945aba3 100644 --- a/app/code/Magento/Customer/etc/db_schema_whitelist.json +++ b/app/code/Magento/Customer/etc/db_schema_whitelist.json @@ -73,7 +73,8 @@ "vat_request_success": true }, "index": { - "CUSTOMER_ADDRESS_ENTITY_PARENT_ID": true + "CUSTOMER_ADDRESS_ENTITY_PARENT_ID": true, + "FTI_BA70344390184AC3F063AB2EB38BC0ED": true }, "constraint": { "PRIMARY": true, diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index cfc62fc99b10e..28b19d61fbdde 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -39,25 +39,18 @@ <bookmark name="bookmarks"/> <columnsControls name="columns_controls"/> <!-- Filter Search --> - <filterSearch name="fulltext"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing_data_source</item> - <item name="chipsProvider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters_chips</item> - <item name="storageConfig" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> - <item name="namespace" xsi:type="string">current.search</item> - </item> - </item> - </argument> + <filterSearch name="fulltext" provider="customer_address_listing.customer_address_listing_data_source"> + <settings> + <chipsProvider>customer_address_listing.customer_address_listing.listing_top.listing_filters_chips</chipsProvider> + <storageConfig> + <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</param> + <param name="namespace" xsi:type="string">current.search</param> + </storageConfig> + </settings> </filterSearch> <filters name="listing_filters"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> - <item name="storageConfig" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> - <item name="namespace" xsi:type="string">current.filters</item> - </item> <item name="childDefaults" xsi:type="array"> <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</item> <item name="imports" xsi:type="array"> @@ -66,6 +59,12 @@ </item> </item> </argument> + <settings> + <storageConfig> + <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</param> + <param name="namespace" xsi:type="string">current.filters</param> + </storageConfig> + </settings> </filters> <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> <action name="delete"> diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 6fc8fcac6099f..17d4e7aab5cd3 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -328,10 +328,9 @@ </settings> </component> - <button name="edit_billing_address"> + <button name="edit_billing_address" component="Magento_Customer/js/address/default-address"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Customer/js/address/default-address</item> <item name="buttonClasses" xsi:type="string">edit-default-billing-address-button</item> <item name="actions" xsi:type="array"> <item name="0" xsi:type="array"> @@ -375,10 +374,9 @@ </settings> </component> - <button name="edit_shipping_address"> + <button name="edit_shipping_address" component="Magento_Customer/js/address/default-address"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Customer/js/address/default-address</item> <item name="buttonClasses" xsi:type="string">edit-default-shipping-address-button</item> <item name="actions" xsi:type="array"> <item name="0" xsi:type="array"> @@ -405,11 +403,10 @@ </imports> </settings> </button> - <button name="add_address"> + <button name="add_address" component="Magento_Customer/js/address/default-address"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="formElement" xsi:type="string">container</item> - <item name="component" xsi:type="string">Magento_Customer/js/address/default-address</item> <item name="buttonClasses" xsi:type="string">add-new-address-button</item> <item name="actions" xsi:type="array"> <item name="0" xsi:type="array"> diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php index c6741f76e0538..5a4a426b58cda 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -86,9 +86,7 @@ public function testSaveActionWithValidAddressData() $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); $this->customerAddress->execute(); - /** - * Check that errors was generated and set to session - */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); /** @@ -220,4 +218,36 @@ public function testSaveActionWithExistingAdresses() $addresses = $customer->getAddresses(); $this->assertCount(4, $addresses); } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + */ + public function testValidateCustomerWithAddressFailure() + { + $customer = $this->customerRepository->get('customer@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => '', + 'lastname' => '', + 'street' => ['update street'], + 'city' => 'update city', + 'postcode' => '01001', + 'telephone' => '', + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages( + $this->equalTo(['One or more input exceptions have occurred.']), + \Magento\Framework\Message\MessageInterface::TYPE_ERROR + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php index 2fe49efd74a6d..292d61c392d06 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php @@ -122,226 +122,6 @@ public function testSaveActionWithInvalidFormData() $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new')); } - /** - * @magentoDbIsolation enabled - */ - public function testSaveActionWithInvalidCustomerAddressData() - { - $post = [ - 'customer' => [ - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 0, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'example@domain.com', - 'default_billing' => '_item1', - ], - 'address' => ['_item1' => []], - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/save'); - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - /** - * Check that customer data were set to session - */ - $this->assertArraySubset( - $post, - $this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerFormData() - ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new')); - } - - /** - * @magentoDbIsolation enabled - */ - public function testSaveActionWithValidCustomerDataAndValidAddressData() - { - $post = [ - 'customer' => [ - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 0, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'example@domain.com', - 'default_billing' => '_item1', - 'password' => 'password', - ], - 'address' => [ - '_item1' => [ - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'street' => ['test street'], - 'city' => 'test city', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '01001', - 'telephone' => '+7000000001', - 'default_billing' => 'true', - ], - ], - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setParam('back', '1'); - - // Emulate setting customer data to session in editAction - $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); - - $this->dispatch('backend/customer/index/save'); - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); - - /** - * Check that customer data were cleaned after it was saved successfully - */ - $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - - /** - * Check that customer id set and addresses saved - */ - $registry = $this->objectManager->get(\Magento\Framework\Registry::class); - $customerId = $registry->registry(RegistryConstants::CURRENT_CUSTOMER_ID); - $customer = $this->customerRepository->getById($customerId); - $this->assertEquals('test firstname', $customer->getFirstname()); - $addresses = $customer->getAddresses(); - $this->assertEquals(1, count($addresses)); - $this->assertNotEquals(0, $this->accountManagement->getDefaultBillingAddress($customerId)); - $this->assertNull($this->accountManagement->getDefaultShippingAddress($customerId)); - - $urlPatternParts = [ - $this->_baseControllerUrl . 'edit', - 'id/' . $customerId, - 'back/1', - ]; - $urlPattern = '/^' . str_replace('/', '\/', implode('(/.*/)|/', $urlPatternParts)) . '/'; - - $this->assertRedirect( - $this->matchesRegularExpression($urlPattern) - ); - - /** @var \Magento\Newsletter\Model\Subscriber $subscriber */ - $subscriber = $this->objectManager->get(\Magento\Newsletter\Model\SubscriberFactory::class)->create(); - $this->assertEmpty($subscriber->getId()); - $subscriber->loadByCustomerId($customerId); - $this->assertEmpty($subscriber->getId()); - } - - /** - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testSaveActionExistingCustomerAndExistingAddressData() - { - $post = [ - 'customer' => [ - 'entity_id' => '1', - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'customer@example.com', - 'new_password' => 'auto', - 'sendemail_store_id' => '1', - 'sendemail' => '1', - 'created_at' => '2000-01-01 00:00:00', - 'default_shipping' => '_item1', - 'default_billing' => 1, - ], - 'address' => [ - '1' => [ - 'firstname' => 'update firstname', - 'lastname' => 'update lastname', - 'street' => ['update street'], - 'city' => 'update city', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '01001', - 'telephone' => '+7000000001', - 'default_billing' => 'true', - ], - '_item1' => [ - 'firstname' => 'new firstname', - 'lastname' => 'new lastname', - 'street' => ['new street'], - 'city' => 'new city', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '01001', - 'telephone' => '+7000000001', - 'default_shipping' => 'true', - ], - '_template_' => [ - 'firstname' => '', - 'lastname' => '', - 'street' => [], - 'city' => '', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '', - 'telephone' => '', - ], - ], - 'subscription' => '', - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setParam('id', 1); - $this->dispatch('backend/customer/index/save'); - - /** Check that success message is set */ - $this->assertSessionMessages( - $this->equalTo(['You saved the customer.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - - /** Check that customer id set and addresses saved */ - $registry = $this->objectManager->get(\Magento\Framework\Registry::class); - $customerId = $registry->registry(RegistryConstants::CURRENT_CUSTOMER_ID); - $customer = $this->customerRepository->getById($customerId); - $this->assertEquals('test firstname', $customer->getFirstname()); - - /** - * Addresses should be removed by - * \Magento\Customer\Model\ResourceModel\Customer::_saveAddresses during _afterSave - * addressOne - updated - * addressTwo - removed - * addressThree - removed - * _item1 - new address - */ - $addresses = $customer->getAddresses(); - $this->assertEquals(2, count($addresses)); - $updatedAddress = $this->addressRepository->getById(1); - $this->assertEquals('update firstname', $updatedAddress->getFirstname()); - $this->assertTrue($updatedAddress->isDefaultBilling()); - $this->assertEquals($updatedAddress->getId(), $customer->getDefaultBilling()); - $newAddress = $this->accountManagement->getDefaultShippingAddress($customerId); - $this->assertEquals('new firstname', $newAddress->getFirstname()); - - /** @var \Magento\Newsletter\Model\Subscriber $subscriber */ - $subscriber = $this->objectManager->get(\Magento\Newsletter\Model\SubscriberFactory::class)->create(); - $this->assertEmpty($subscriber->getId()); - $subscriber->loadByCustomerId($customerId); - $this->assertNotEmpty($subscriber->getId()); - $this->assertEquals(1, $subscriber->getStatus()); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); - } - /** * @magentoDataFixture Magento/Newsletter/_files/subscribers.php */ @@ -544,7 +324,7 @@ public function testNewAction() /** * Test the editing of a new customer that has not been saved but the page has been reloaded */ - public function testNewActionWithCustomerData() + public function te1stNewActionWithCustomerData() { $customerData = [ 'customer_id' => 0, @@ -679,59 +459,6 @@ public function testValidateCustomerWithAddressSuccess() $this->assertEquals('{"error":0}', $body); } - /** - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoDataFixture Magento/Customer/_files/customer_address.php - */ - public function testValidateCustomerWithAddressFailure() - { - $customerData = [ - 'customer' => [ - 'entity_id' => '1', - 'middlename' => 'new middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => '', - 'lastname' => '', - 'email' => '*', - 'default_shipping' => '_item1', - 'new_password' => 'auto', - 'sendemail_store_id' => '1', - 'sendemail' => '1', - ], - 'address' => [ - '1' => [ - 'firstname' => '', - 'lastname' => '', - 'street' => ['update street'], - 'city' => 'update city', - 'postcode' => '01001', - 'telephone' => '', - ], - '_template_' => [ - 'lastname' => '', - 'street' => [], - 'city' => '', - 'country_id' => 'US', - 'postcode' => '', - 'telephone' => '', - ], - ], - ]; - /** - * set customer data - */ - $this->getRequest()->setPostValue($customerData)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/validate'); - $body = $this->getResponse()->getBody(); - - $this->assertContains('{"error":true,"messages":', $body); - $this->assertContains('\"First Name\" is a required value', $body); - $this->assertContains('\"Last Name\" is a required value.', $body); - $this->assertContains('\"Country\" is a required value.', $body); - $this->assertContains('\"Phone Number\" is a required value.', $body); - } - /** * @magentoDbIsolation enabled */ From c2100db5bd2ec177f0fdf5a40ff9ac97e46c0b1a Mon Sep 17 00:00:00 2001 From: Giel Berkers <giel.berkers@isaac.nl> Date: Tue, 6 Nov 2018 11:15:58 +0100 Subject: [PATCH 0495/1158] [REFACTOR] Split the method to lower cyclomatic complexity --- .../Product/CategoryLinkTest.php | 100 ++++++++++-------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php index c0c061ab8a704..5a1a5906ec4b9 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CategoryLinkTest.php @@ -134,53 +134,8 @@ public function testSaveCategoryLinks($newCategoryLinks, $dbCategoryLinks, $affe foreach ($affectedIds as $type => $ids) { $expectedResult = array_merge($expectedResult, $ids); - // Verify if the correct insert, update and/or delete actions are performed: - switch ($type) { - case 'insert': - $this->connectionMock - ->expects($this->exactly(empty($ids) ? 0 : 1)) - ->method('insertArray') - ->with( - $this->anything(), - $this->anything(), - $this->callback(function ($data) use ($ids) { - $foundIds = []; - foreach ($data as $row) { - $foundIds[] = $row['category_id']; - } - return $ids === $foundIds; - }) - ); - break; - case 'update': - $this->connectionMock - ->expects($this->exactly(empty($ids) ? 0 : 1)) - ->method('insertOnDuplicate') - ->with( - $this->anything(), - $this->callback(function ($data) use ($ids) { - $foundIds = []; - foreach ($data as $row) { - $foundIds[] = $row['category_id']; - } - return $ids === $foundIds; - }) - ); - break; - case 'delete': - $this->connectionMock - ->expects($this->exactly(empty($ids) ? 0 : 1)) - ->method('delete') - // Verify that the correct category ID's are touched: - ->with( - $this->anything(), - $this->callback(function ($data) use ($ids) { - return array_values($data)[1] === $ids; - }) - ); - break; - } + $this->setupExpectationsForConnection($type, $ids); } $actualResult = $this->model->saveCategoryLinks($product, $newCategoryLinks); @@ -273,4 +228,57 @@ public function getCategoryLinksDataProvider() ] ]; } + + /** + * @param $type + * @param $ids + */ + private function setupExpectationsForConnection($type, $ids): void + { + switch ($type) { + case 'insert': + $this->connectionMock + ->expects($this->exactly(empty($ids) ? 0 : 1)) + ->method('insertArray') + ->with( + $this->anything(), + $this->anything(), + $this->callback(function ($data) use ($ids) { + $foundIds = []; + foreach ($data as $row) { + $foundIds[] = $row['category_id']; + } + return $ids === $foundIds; + }) + ); + break; + case 'update': + $this->connectionMock + ->expects($this->exactly(empty($ids) ? 0 : 1)) + ->method('insertOnDuplicate') + ->with( + $this->anything(), + $this->callback(function ($data) use ($ids) { + $foundIds = []; + foreach ($data as $row) { + $foundIds[] = $row['category_id']; + } + return $ids === $foundIds; + }) + ); + break; + case 'delete': + $this->connectionMock + ->expects($this->exactly(empty($ids) ? 0 : 1)) + ->method('delete') + // Verify that the correct category ID's are touched: + ->with( + $this->anything(), + $this->callback(function ($data) use ($ids) { + return array_values($data)[1] === $ids; + }) + ); + break; + } + } } From 35112c4015f6912dd29c7b65c83ee1aef9fe04b8 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Tue, 6 Nov 2018 12:30:50 +0200 Subject: [PATCH 0496/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - UI component declaration fixes --- .../ui_component/customer_address_listing.xml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 28b19d61fbdde..6c97a6da5e9e2 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -49,21 +49,17 @@ </settings> </filterSearch> <filters name="listing_filters"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="childDefaults" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</item> - <item name="imports" xsi:type="array"> - <item name="visible" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item> - </item> - </item> - </item> - </argument> <settings> <storageConfig> <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</param> <param name="namespace" xsi:type="string">current.filters</param> </storageConfig> + <childDefaults> + <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</param> + <param name="imports" xsi:type="array"> + <item name="visible" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item> + </param> + </childDefaults> </settings> </filters> <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> From 46e06440229c51f35ff96123b575be4b21fa9f1e Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Tue, 6 Nov 2018 13:40:36 +0300 Subject: [PATCH 0497/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 3fb7e9ecc8b4b..88758d63d0148 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -47,6 +47,7 @@ define([ if (~~this.currentPage() === this.pages()) { return false; } + for (index; index < recordData.length; index++) { recordData[index].position = index + offset; } From 4803537b41f6ca2b059c2a64a3c2a03d7c9482e1 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Tue, 6 Nov 2018 13:03:59 +0200 Subject: [PATCH 0498/1158] #13157 - Last Ordered Items block - bad js code --- .../Sales/view/frontend/web/js/view/last-ordered-items.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js b/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js index 9897666653df9..74465128f8c72 100644 --- a/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js +++ b/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js @@ -5,8 +5,9 @@ define([ 'uiComponent', - 'Magento_Customer/js/customer-data' -], function (Component, customerData) { + 'Magento_Customer/js/customer-data', + 'underscore' +], function (Component, customerData, _) { 'use strict'; return Component.extend({ From bfd8feb724a44beeee3945f06fc5946a1529b86d Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Tue, 6 Nov 2018 15:24:28 +0300 Subject: [PATCH 0499/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 88758d63d0148..fbd134cdf29d8 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -54,7 +54,6 @@ define([ this.recordData(recordData); }, - /** * Update position for element after position from another page is entered * From c0c1d76192b57fe524d0b9d2672282221ea8b011 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 6 Nov 2018 14:07:03 +0100 Subject: [PATCH 0500/1158] Added checkout module dependency --- app/code/Magento/QuoteGraphQl/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index c9900dd5f3150..f0d2eea9bcaf6 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -6,6 +6,7 @@ "php": "~7.1.3||~7.2.0", "magento/framework": "*", "magento/module-quote": "*", + "magento/module-checkout": "*", "magento/module-catalog": "*", "magento/module-store": "*" }, From 591168ed6ab3e62a374f5c32bc4e5fb8a406740e Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Tue, 6 Nov 2018 15:52:45 +0200 Subject: [PATCH 0501/1158] ENGCOM-3358: [Forwardport] Prevent rendering of 'Ship here' button to select a shipping item if it is already selected #18986 Fix function test. --- .../Test/Mftf/Section/CheckoutShippingMethodsSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml index ceb4505c79693..56ed42fbfbbea 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml @@ -14,7 +14,7 @@ <element name="shippingMethodRow" type="text" selector=".form.methods-shipping table tbody tr"/> <element name="checkShippingMethodByName" type="radio" selector="//div[@id='checkout-shipping-method-load']//td[contains(., '{{var1}}')]/..//input" parameterized="true"/> <element name="shippingMethodRowByName" type="text" selector="//div[@id='checkout-shipping-method-load']//td[contains(., '{{var1}}')]/.." parameterized="true"/> - <element name="shipHereButton" type="button" selector="//button[contains(@class, 'action-select-shipping-item')]/parent::div/following-sibling::div/button[contains(@class, 'action-select-shipping-item')]"/> + <element name="shipHereButton" type="button" selector="//div/following-sibling::div/button[contains(@class, 'action-select-shipping-item')]"/> <element name="shippingMethodLoader" type="button" selector="//div[contains(@class, 'checkout-shipping-method')]/following-sibling::div[contains(@class, 'loading-mask')]"/> </section> </sections> From c3b4a8078771dd6ba76b1d00d9709a37b81c7677 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 6 Nov 2018 15:00:00 +0100 Subject: [PATCH 0502/1158] Covered most cases except authorisation --- .../Quote/SetShippingMethodOnCartTest.php | 160 +++++++++++++++--- 1 file changed, 132 insertions(+), 28 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php index 64c7cbf9fd42e..932c8ac386c27 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php @@ -39,6 +39,9 @@ class SetShippingMethodOnCartTest extends GraphQlAbstract */ private $quoteIdToMaskedId; + /** + * @inheritdoc + */ protected function setUp() { $objectManager = Bootstrap::getObjectManager(); @@ -51,26 +54,139 @@ protected function setUp() /** * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php */ - public function testSetShippingOnCart() + public function testSetShippingMethodOnCart() { + $shippingCarrierCode = 'flatrate'; + $shippingMethodCode = 'flatrate'; $this->quoteResource->load( $this->quote, 'test_order_1', 'reserved_order_id' ); + $shippingAddress = $this->quote->getShippingAddress(); + $shippingAddressId = $shippingAddress->getId(); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = $this->prepareMutationQuery( + $maskedQuoteId, + $shippingMethodCode, + $shippingCarrierCode, + $shippingAddressId + ); + + $response = $this->sendRequestWithToken($query); + + self::assertArrayHasKey('setShippingMethodsOnCart', $response); + self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']); + self::assertEquals($maskedQuoteId, $response['setShippingMethodsOnCart']['cart']['cart_id']); + $addressesInformation = $response['setShippingMethodsOnCart']['cart']['addresses']; + self::assertCount(2, $addressesInformation); + self::assertEquals( + $addressesInformation[0]['selected_shipping_method']['code'], + $shippingCarrierCode . '_' . $shippingMethodCode + ); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetShippingMethodWithWrongCartId() + { + $shippingCarrierCode = 'flatrate'; + $shippingMethodCode = 'flatrate'; + $shippingAddressId = '1'; + $maskedQuoteId = 'invalid'; + + $query = $this->prepareMutationQuery( + $maskedQuoteId, + $shippingMethodCode, + $shippingCarrierCode, + $shippingAddressId + ); + + self::expectExceptionMessage("Could not find a cart with ID \"$maskedQuoteId\""); + $this->sendRequestWithToken($query); + } + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetNonExistingShippingMethod() + { + $shippingCarrierCode = 'non'; + $shippingMethodCode = 'existing'; + $this->quoteResource->load( + $this->quote, + 'test_order_1', + 'reserved_order_id' + ); $shippingAddress = $this->quote->getShippingAddress(); $shippingAddressId = $shippingAddress->getId(); $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); - $query = <<<QUERY + + $query = $this->prepareMutationQuery( + $maskedQuoteId, + $shippingMethodCode, + $shippingCarrierCode, + $shippingAddressId + ); + + self::expectExceptionMessage("Carrier with such method not found: $shippingCarrierCode, $shippingMethodCode"); + $this->sendRequestWithToken($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetShippingMethodWithNonExistingAddress() + { + $shippingCarrierCode = 'flatrate'; + $shippingMethodCode = 'flatrate'; + $this->quoteResource->load( + $this->quote, + 'test_order_1', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + $shippingAddressId = '-20'; + + $query = $this->prepareMutationQuery( + $maskedQuoteId, + $shippingMethodCode, + $shippingCarrierCode, + $shippingAddressId + ); + + self::expectExceptionMessage('The shipping address is missing. Set the address and try again.'); + $this->sendRequestWithToken($query); + } + + // TODO: TBD - add check for guest with attempt to set shipping method to the customer's shopping cart + + /** + * Generates query for setting the specified shipping method on cart + * + * @param string $maskedQuoteId + * @param string $shippingMethodCode + * @param string $shippingCarrierCode + * @param string $shippingAddressId + * @return string + */ + private function prepareMutationQuery( + string $maskedQuoteId, + string $shippingMethodCode, + string $shippingCarrierCode, + string $shippingAddressId + ) : string { + return <<<QUERY mutation { setShippingMethodsOnCart(input: { cart_id: "$maskedQuoteId", shipping_methods: [ { - shipping_method_code: "flatrate" - shipping_carrier_code: "flatrate" + shipping_method_code: "$shippingMethodCode" + shipping_carrier_code: "$shippingCarrierCode" cart_address_id: $shippingAddressId } ]}) { @@ -78,22 +194,6 @@ public function testSetShippingOnCart() cart { cart_id, addresses { - firstname - lastname - company - address_type - city - street - region { - code - label - } - postcode - country { - code - label - } - selected_shipping_method { code label @@ -104,17 +204,21 @@ public function testSetShippingOnCart() } QUERY; + } + + /** + * Sends a GraphQL request with using a bearer token + * + * @param string $query + * @return array + * @throws \Magento\Framework\Exception\AuthenticationException + */ + private function sendRequestWithToken(string $query): array + { $customerToken = $this->customerTokenService->createCustomerAccessToken('customer@example.com', 'password'); $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; - $response = $this->graphQlQuery($query, [], '', $headerMap); - - self::assertArrayHasKey('setShippingMethodsOnCart', $response); - self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']); - self::assertEquals($maskedQuoteId, $response['setShippingMethodsOnCart']['cart']['cart_id']); - // TODO: check shipping method code and description + return $this->graphQlQuery($query, [], '', $headerMap); } - - // TODO: cover all other cases } From 1320b9d45115831588cb8396fba9171304b27fb3 Mon Sep 17 00:00:00 2001 From: Nikita Chubukov <nikita_chubukov@epam.com> Date: Thu, 25 Oct 2018 14:26:50 +0300 Subject: [PATCH 0503/1158] MAGETWO-95816: Invoice PDF contain different address when use arabic symbols - Reverse text with Arabic characters --- .../Sales/Model/Order/Pdf/AbstractPdf.php | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php b/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php index 85e34f560bb7b..8cdc90972bbb0 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php @@ -363,6 +363,38 @@ protected function _calcAddressHeight($address) return $y; } + /** + * Detect an input string is Arabic + * + * @param string $subject + * @return bool + */ + private function isArabic(string $subject): bool + { + return (preg_match('/\p{Arabic}/u', $subject) > 0); + } + + /** + * Reverse text with Arabic characters + * + * @param string $string + * @return string + */ + private function reverseArabicText($string) + { + $splitText = explode(' ', $string); + for ($i = 0; $i < count($splitText); $i++) { + if ($this->isArabic($splitText[$i])) { + for ($j = $i + 1; $j < count($splitText); $j++) { + $tmp = $this->string->strrev($splitText[$j]); + $splitText[$j] = $this->string->strrev($splitText[$i]); + $splitText[$i] = $tmp; + } + } + } + return implode(' ', $splitText); + } + /** * Insert order to pdf page * @@ -474,7 +506,7 @@ protected function insertOrder(&$page, $obj, $putOrderId = true) if ($value !== '') { $text = []; foreach ($this->string->split($value, 45, true, true) as $_value) { - $text[] = $_value; + $text[] = ($this->isArabic($_value)) ? $this->reverseArabicText($_value) : $_value; } foreach ($text as $part) { $page->drawText(strip_tags(ltrim($part)), 35, $this->y, 'UTF-8'); @@ -491,7 +523,7 @@ protected function insertOrder(&$page, $obj, $putOrderId = true) if ($value !== '') { $text = []; foreach ($this->string->split($value, 45, true, true) as $_value) { - $text[] = $_value; + $text[] = ($this->isArabic($_value)) ? $this->reverseArabicText($_value) : $_value; } foreach ($text as $part) { $page->drawText(strip_tags(ltrim($part)), 285, $this->y, 'UTF-8'); From 9861eea014c352eb28d76a886db246c4aeaa6bee Mon Sep 17 00:00:00 2001 From: Vital_Pantsialeyeu <vital_pantsialeyeu@epam.com> Date: Tue, 6 Nov 2018 17:33:30 +0300 Subject: [PATCH 0504/1158] MAGETWO-70379: UI components Date filter field has non-localized date format - Changed the logic of date formatting --- .../Ui/Component/Listing/Columns/Date.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/code/Magento/Ui/Component/Listing/Columns/Date.php b/app/code/Magento/Ui/Component/Listing/Columns/Date.php index 1c9916a941458..50cebf1bf6016 100644 --- a/app/code/Magento/Ui/Component/Listing/Columns/Date.php +++ b/app/code/Magento/Ui/Component/Listing/Columns/Date.php @@ -47,6 +47,27 @@ public function __construct( parent::__construct($context, $uiComponentFactory, $components, $data); } + /** + * @inheritdoc + */ + public function prepare() + { + $config = $this->getData('config'); + $config['filter'] = [ + 'filterType' => 'dateRange', + 'templates' => [ + 'date' => [ + 'options' => [ + 'dateFormat' => $this->timezone->getDateFormatWithLongYear() + ] + ] + ] + ]; + $this->setData('config', $config); + + parent::prepare(); + } + /** * @inheritdoc */ From 5934b231fe89fde967936124f714b929f2a1aada Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Tue, 6 Nov 2018 17:38:53 +0300 Subject: [PATCH 0505/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../adminhtml/web/js/grouped-product-grid.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index fbd134cdf29d8..9cb0a00dc9521 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -57,8 +57,8 @@ define([ /** * Update position for element after position from another page is entered * - * @param data - * @param event + * @param {Object} data + * @param {Object} event */ updateGridPosition: function (data, event) { var inputValue = parseInt(event.target.value, 10), @@ -102,8 +102,8 @@ define([ /** * Get updated record index * - * @param recordData - * @param recordId + * @param {Array} recordData + * @param {Number} recordId * @return {number} */ getUpdatedRecordIndex: function (recordData, recordId) { @@ -114,7 +114,7 @@ define([ /** * - * @param recordData to reprocess + * @param {Array} recordData to reprocess */ reloadGridData: function (recordData) { this.recordData(recordData.sort(function (a, b) { @@ -127,7 +127,7 @@ define([ /** * Event handler for "Send to bottom" button * - * @param positionObj + * @param {Object} positionObj * @return {boolean} */ sendToBottom: function (positionObj) { @@ -151,7 +151,7 @@ define([ /** * Event handler for "Send to top" button * - * @param positionObj + * @param {Object} positionObj * @returns {boolean} */ sendToTop: function (positionObj) { @@ -176,7 +176,7 @@ define([ /** * Get element from grid for update * - * @param object + * @param {Object} object * @return {*} */ getObjectToUpdate: function (object) { @@ -188,7 +188,7 @@ define([ /** * Value function for position input * - * @param data + * @param {Object} data * @return {number} */ getCalculatedPosition: function (data) { From a34906d3bcbf7f12afe9f8a9bd5e750c9bc81bef Mon Sep 17 00:00:00 2001 From: Vital_Pantsialeyeu <vital_pantsialeyeu@epam.com> Date: Tue, 6 Nov 2018 17:47:16 +0300 Subject: [PATCH 0506/1158] MAGETWO-70379: UI components Date filter field has non-localized date format - Fixed static tests --- app/code/Magento/Ui/Component/Listing/Columns/Date.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Ui/Component/Listing/Columns/Date.php b/app/code/Magento/Ui/Component/Listing/Columns/Date.php index 50cebf1bf6016..ad876b66b6038 100644 --- a/app/code/Magento/Ui/Component/Listing/Columns/Date.php +++ b/app/code/Magento/Ui/Component/Listing/Columns/Date.php @@ -11,6 +11,8 @@ use Magento\Framework\Stdlib\DateTime\TimezoneInterface; /** + * Date format column + * * @api * @since 100.0.2 */ From 9badfbde6544b9cc4339316903c073551dac6ac5 Mon Sep 17 00:00:00 2001 From: vtymchynskyi <vtymchynskyi@magento.com> Date: Tue, 6 Nov 2018 17:15:59 +0200 Subject: [PATCH 0507/1158] MAGETWO-95539: [2.3] Moving Category generate duplicate url_rewrite when 4th level category exist and is translated - Fixed url rewrites regeneration after category moving --- .../Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php index 8147818135edc..a2767f76cfecb 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php @@ -85,6 +85,7 @@ public function test(Store $storeView, Category $childCategory, Category $parent $this->catalogCategoryEdit->getFormPageActions()->selectStoreView($storeView->getName()); $this->catalogCategoryEdit->getEditForm()->fill($categoryUpdates); $this->catalogCategoryEdit->getFormPageActions()->save(); + $this->catalogCategoryEdit->getFormPageActions()->selectStoreView('All Store Views'); $this->catalogCategoryIndex->getTreeCategories()->assignCategory( $parentCategory->getName(), $childCategory->getName() From bf5ad21fc451c17b496f5a24280600e5c66c1aba Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Tue, 6 Nov 2018 18:36:03 +0300 Subject: [PATCH 0508/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../view/adminhtml/web/js/grouped-product-grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 9cb0a00dc9521..c06f615ae48e6 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -104,7 +104,7 @@ define([ * * @param {Array} recordData * @param {Number} recordId - * @return {number} + * @return {Number} */ getUpdatedRecordIndex: function (recordData, recordId) { return recordData.map(function (o) { From 418d0cabbe129eb0fcc9cf793213de7217292be8 Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Tue, 6 Nov 2018 11:18:38 -0600 Subject: [PATCH 0509/1158] MAGETWO-95745: Signifyd case not created for WorldPay --- app/code/Magento/Checkout/Controller/Onepage/Success.php | 5 ++++- app/code/Magento/Signifyd/etc/events.xml | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Controller/Onepage/Success.php b/app/code/Magento/Checkout/Controller/Onepage/Success.php index 7db5cd8f012c7..e0872b425cc7c 100644 --- a/app/code/Magento/Checkout/Controller/Onepage/Success.php +++ b/app/code/Magento/Checkout/Controller/Onepage/Success.php @@ -26,7 +26,10 @@ public function execute() $resultPage = $this->resultPageFactory->create(); $this->_eventManager->dispatch( 'checkout_onepage_controller_success_action', - ['order_ids' => [$session->getLastOrderId()]] + [ + 'order_ids' => [$session->getLastOrderId()], + 'order' => $session->getLastRealOrder() + ] ); return $resultPage; } diff --git a/app/code/Magento/Signifyd/etc/events.xml b/app/code/Magento/Signifyd/etc/events.xml index d5ba6e5a99227..e6418e2fdb6b4 100644 --- a/app/code/Magento/Signifyd/etc/events.xml +++ b/app/code/Magento/Signifyd/etc/events.xml @@ -15,4 +15,7 @@ <event name="paypal_checkout_success"> <observer name="signifyd_place_order_checkout_success_observer" instance="Magento\Signifyd\Observer\PlaceOrder" /> </event> + <event name="checkout_onepage_controller_success_action"> + <observer name="signifyd_place_order_checkout_success_observer" instance="Magento\Signifyd\Observer\PlaceOrder" /> + </event> </config> From 25fd4670c9988c7fe7b365f077f25dfa6d01839a Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Tue, 6 Nov 2018 19:19:55 +0200 Subject: [PATCH 0510/1158] GraphQl-45: Product textarea field format --- .../Product/ProductComplexTextAttribute.php | 2 +- .../Resolver/ComplexTextValue/HtmlFormat.php | 38 ----- app/code/Magento/GraphQl/etc/schema.graphqls | 2 +- .../Magento/GraphQl/Catalog/CategoryTest.php | 8 +- .../Catalog/ProductTextAttributesTest.php | 142 ++++++++++++++++++ .../GraphQl/Catalog/ProductViewTest.php | 34 ----- .../ProductWithDescriptionDirectivesTest.php | 65 -------- 7 files changed, 150 insertions(+), 141 deletions(-) delete mode 100644 app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductTextAttributesTest.php delete mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductWithDescriptionDirectivesTest.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php index 7cf7225d0f61c..96519d6191eee 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductComplexTextAttribute.php @@ -52,6 +52,6 @@ public function resolve( $fieldName = $field->getName(); $renderedValue = $this->outputHelper->productAttribute($product, $product->getData($fieldName), $fieldName); - return ['html' => $renderedValue]; + return ['html' => $renderedValue ?? '']; } } diff --git a/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php b/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php deleted file mode 100644 index fffca765faba6..0000000000000 --- a/app/code/Magento/GraphQl/Model/Resolver/ComplexTextValue/HtmlFormat.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\GraphQl\Model\Resolver\ComplexTextValue; - -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; - -/** - * HTML format for complex text value. - * - * Initially, a value from parent resolver should be in HTML format, therefore, there is no any customization. - */ -class HtmlFormat implements ResolverInterface -{ - /** - * @inheritdoc - */ - public function resolve( - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ): ?string { - if (!isset($value['html'])) { - throw new GraphQlInputException(__('"html" value should be specified')); - } - - return $value['html']; - } -} diff --git a/app/code/Magento/GraphQl/etc/schema.graphqls b/app/code/Magento/GraphQl/etc/schema.graphqls index 991c320860622..2281495d059e1 100644 --- a/app/code/Magento/GraphQl/etc/schema.graphqls +++ b/app/code/Magento/GraphQl/etc/schema.graphqls @@ -38,5 +38,5 @@ enum SortEnum @doc(description: "This enumeration indicates whether to return re } type ComplexTextValue { - html: String! @doc(description: "HTML format") @resolver(class: "\\Magento\\GraphQl\\Model\\Resolver\\ComplexTextValue\\HtmlFormat") + html: String! @doc(description: "HTML format") } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php index eff2e96f4b112..adc3a58e4f8dc 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php @@ -132,7 +132,9 @@ public function testCategoryProducts() attribute_set_id country_of_manufacture created_at - description + description { + html + } gift_message_available id categories { @@ -223,7 +225,9 @@ public function testCategoryProducts() position sku } - short_description + short_description { + html + } sku small_image { path diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductTextAttributesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductTextAttributesTest.php new file mode 100644 index 0000000000000..999e1cc7fca3d --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductTextAttributesTest.php @@ -0,0 +1,142 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Catalog; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; + +class ProductTextAttributesTest extends GraphQlAbstract +{ + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + protected function setUp() + { + $this->productRepository = Bootstrap::getObjectManager()::getInstance()->get(ProductRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testProductTextAttributes() + { + $productSku = 'simple'; + + $query = <<<QUERY +{ + products(filter: {sku: {eq: "{$productSku}"}}) + { + items { + sku + description { + html + } + short_description { + html + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + + $this->assertEquals( + $productSku, + $response['products']['items'][0]['sku'] + ); + $this->assertEquals( + 'Short description', + $response['products']['items'][0]['short_description']['html'] + ); + $this->assertEquals( + 'Description with <b>html tag</b>', + $response['products']['items'][0]['description']['html'] + ); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php + */ + public function testProductWithoutFilledTextAttributes() + { + $productSku = 'virtual-product'; + + $query = <<<QUERY +{ + products(filter: {sku: {eq: "{$productSku}"}}) + { + items { + sku + description { + html + } + short_description { + html + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + + $this->assertEquals( + $productSku, + $response['products']['items'][0]['sku'] + ); + $this->assertEquals( + '', + $response['products']['items'][0]['short_description']['html'] + ); + $this->assertEquals( + '', + $response['products']['items'][0]['description']['html'] + ); + } + + /** + * Test for checking that product fields with directives allowed are rendered correctly + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoApiDataFixture Magento/Cms/_files/block.php + */ + public function testHtmlDirectivesRendering() + { + $productSku = 'simple'; + $cmsBlockId = 'fixture_block'; + $assertionCmsBlockText = 'Fixture Block Title'; + + $product = $this->productRepository->get($productSku, false, null, true); + $product->setDescription('Test: {{block id="' . $cmsBlockId . '"}}'); + $product->setShortDescription('Test: {{block id="' . $cmsBlockId . '"}}'); + $this->productRepository->save($product); + + $query = <<<QUERY +{ + products(filter: {sku: {eq: "{$productSku}"}}) { + items { + description { + html + } + short_description { + html + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + + self::assertContains($assertionCmsBlockText, $response['products']['items'][0]['description']['html']); + self::assertNotContains('{{block id', $response['products']['items'][0]['description']['html']); + self::assertContains($assertionCmsBlockText, $response['products']['items'][0]['short_description']['html']); + self::assertNotContains('{{block id', $response['products']['items'][0]['short_description']['html']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php index 0ec63374be869..a3d0bb28da14a 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php @@ -44,9 +44,6 @@ public function testQueryAllFieldsSimpleProduct() attribute_set_id country_of_manufacture created_at - description { - html - } gift_message_available id categories { @@ -205,9 +202,6 @@ public function testQueryAllFieldsSimpleProduct() position sku } - short_description { - html - } sku small_image { path @@ -266,7 +260,6 @@ public function testQueryAllFieldsSimpleProduct() $this->assertArrayHasKey(0, $response['products']['items']); $this->assertBaseFields($product, $response['products']['items'][0]); $this->assertEavAttributes($product, $response['products']['items'][0]); - $this->assertComplexTextAttributes($product, $response['products']['items'][0]); $this->assertOptions($product, $response['products']['items'][0]); $this->assertTierPrices($product, $response['products']['items'][0]); $this->assertArrayHasKey('websites', $response['products']['items'][0]); @@ -306,7 +299,6 @@ public function testQueryMediaGalleryEntryFieldsSimpleProduct() } country_of_manufacture created_at - description gift_message_available id image @@ -457,7 +449,6 @@ public function testQueryMediaGalleryEntryFieldsSimpleProduct() position sku } - short_description sku small_image { path @@ -947,31 +938,6 @@ private function assertEavAttributes($product, $actualResponse) $this->assertResponseFields($actualResponse, $assertionMap); } - /** - * @param ProductInterface $product - * @param array $actualResponse - */ - private function assertComplexTextAttributes($product, $actualResponse) - { - $eavAttributes = [ - 'description', - 'short_description', - ]; - $assertionMap = []; - foreach ($eavAttributes as $attributeCode) { - $expectedAttribute = $product->getCustomAttribute($attributeCode); - - $assertionMap[] = [ - 'response_field' => $this->eavAttributesToGraphQlSchemaFieldTranslator($attributeCode), - 'expected_value' => $expectedAttribute ? [ - 'html' => $expectedAttribute->getValue() - ] : null - ]; - } - - $this->assertResponseFields($actualResponse, $assertionMap); - } - /** * @param string $eavAttributeCode * @return string diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductWithDescriptionDirectivesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductWithDescriptionDirectivesTest.php deleted file mode 100644 index 8e9bc4dfa2825..0000000000000 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductWithDescriptionDirectivesTest.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\GraphQl\Catalog; - -use Magento\Catalog\Api\Data\ProductInterface; -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\TestFramework\ObjectManager; -use Magento\TestFramework\TestCase\GraphQlAbstract; - -/** - * Test for checking that product fields with directives allowed are rendered correctly - */ -class ProductWithDescriptionDirectivesTest extends GraphQlAbstract -{ - /** - * @var \Magento\TestFramework\ObjectManager - */ - private $objectManager; - - protected function setUp() - { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - } - - /** - * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php - * @magentoApiDataFixture Magento/Cms/_files/block.php - */ - public function testHtmlDirectivesRendered() - { - $productSku = 'simple'; - $cmsBlockId = 'fixture_block'; - $assertionCmsBlockText = 'Fixture Block Title'; - - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); - /** @var ProductInterface $product */ - $product = $productRepository->get($productSku, false, null, true); - $product->setDescription('Test: {{block id="' . $cmsBlockId . '"}}'); - $product->setShortDescription('Test: {{block id="' . $cmsBlockId . '"}}'); - $productRepository->save($product); - - $query = <<<QUERY -{ - products(filter: {sku: {eq: "{$productSku}"}}) { - items { - description - short_description - } - } -} -QUERY; - $response = $this->graphQlQuery($query); - - self::assertContains($assertionCmsBlockText, $response['products']['items'][0]['description']); - self::assertNotContains('{{block id', $response['products']['items'][0]['description']); - self::assertContains($assertionCmsBlockText, $response['products']['items'][0]['short_description']); - self::assertNotContains('{{block id', $response['products']['items'][0]['short_description']); - } -} From 7c21b3b31e5f330e698d6a766cb45e90cf61a3f3 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Tue, 6 Nov 2018 20:36:45 +0200 Subject: [PATCH 0511/1158] graphQl: removed set shipping addresses chain, using di preference instead --- ...essor.php => SetShippingAddressOnCart.php} | 9 ++-- .../Model/Cart/SetShippingAddressesOnCart.php | 49 ------------------- app/code/Magento/QuoteGraphQl/composer.json | 4 +- .../Magento/QuoteGraphQl/etc/graphql/di.xml | 9 +--- .../Quote/SetShippingAddressOnCartTest.php | 46 +++++++++++++++++ 5 files changed, 55 insertions(+), 62 deletions(-) rename app/code/Magento/QuoteGraphQl/Model/Cart/{SetShippingAddressesOnCart/SingleShippingAddressProcessor.php => SetShippingAddressOnCart.php} (92%) delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php similarity index 92% rename from app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php rename to app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php index 41675716c68bf..588d4f65cc565 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart/SingleShippingAddressProcessor.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCart; +namespace Magento\QuoteGraphQl\Model\Cart; use Magento\Authorization\Model\UserContextInterface; use Magento\Customer\Api\Data\AddressInterface; @@ -16,12 +16,11 @@ use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\ShippingAddressManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; -use Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface; /** * Set single shipping address for a specified shopping cart */ -class SingleShippingAddressProcessor implements SetShippingAddressesOnCartInterface +class SetShippingAddressOnCart implements SetShippingAddressesOnCartInterface { /** * @var ShippingAddressManagementInterface @@ -59,7 +58,9 @@ public function __construct( public function execute(ContextInterface $context, CartInterface $cart, array $shippingAddresses): void { if (count($shippingAddresses) > 1) { - return; + throw new GraphQlInputException( + __('Multiple addresses do not allowed here!') + ); } $shippingAddress = current($shippingAddresses); $customerAddressId = $shippingAddress['customer_address_id'] ?? null; diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php deleted file mode 100644 index 8ebcdef1f549a..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Cart; - -use InvalidArgumentException; -use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; -use Magento\Quote\Api\Data\CartInterface; - -/** - * Set shipping addresses for shopping cart processors chain - */ -class SetShippingAddressesOnCart implements SetShippingAddressesOnCartInterface -{ - /** - * @var SetShippingAddressesOnCartInterface[] - */ - private $shippingAddressProcessors; - - /** - * @param array $shippingAddressProcessors - */ - public function __construct( - array $shippingAddressProcessors - ) { - $this->shippingAddressProcessors = $shippingAddressProcessors; - } - - /** - * @inheritdoc - */ - public function execute(ContextInterface $context, CartInterface $cart, array $shippingAddresses): void - { - foreach ($this->shippingAddressProcessors as $shippingAddressProcessor) { - if (!$shippingAddressProcessor instanceof SetShippingAddressesOnCartInterface) { - throw new InvalidArgumentException( - get_class($shippingAddressProcessor) . - ' is not instance of \Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface.' - ); - } - - $shippingAddressProcessor->execute($context, $cart, $shippingAddresses); - } - } -} diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index 485c958718bf3..b3433fdc8fea6 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -8,7 +8,9 @@ "magento/module-quote": "*", "magento/module-catalog": "*", "magento/module-store": "*", - "magento/module-checkout": "*" + "magento/module-checkout": "*", + "magento/module-customer": "*", + "magento/module-authorization": "*" }, "suggest": { "magento/module-graph-ql": "*" diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml index f28d484fa0f6f..e7417d657a0ea 100644 --- a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml @@ -7,14 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface" - type="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCart" /> - <type name="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface"> - <arguments> - <argument name="shippingAddressProcessors" xsi:type="array"> - <item name="singleShippingAddress" xsi:type="object">Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCart\SingleShippingAddressProcessor</item> - </argument> - </arguments> - </type> + type="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressOnCart" /> <virtualType name="multishippingPaymentSpecification" type="Magento\Payment\Model\Method\Specification\Composite"> <arguments> <argument name="specifications" xsi:type="array"> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php index 9771dbbf84c48..48ef8ebb790d1 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php @@ -143,6 +143,52 @@ public function testSetSavedShippingAddressOnCartByGuest() $this->graphQlQuery($query); } + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + * @magentoConfigFixture default_store multishipping/options/checkout_multiple 0 + */ + public function testSetMultipleShippingAddressesOnCartByGuest() + { + $this->quoteResource->load( + $this->quote, + 'test_order_with_simple_product_without_address', + 'reserved_order_id' + ); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + customer_address_id: 1 + }, + { + customer_address_id: 1 + } + ] + } + ) { + cart { + addresses { + firstname + lastname + company + street + city + postcode + telephone + } + } + } +} +QUERY; + self::expectExceptionMessage('Multiple addresses do not allowed here!'); + $this->graphQlQuery($query); + } + /** * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php */ From c8578575c498690cd672764c374ddafec18dcc90 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Tue, 6 Nov 2018 20:38:08 +0200 Subject: [PATCH 0512/1158] graphQl: fixed composer json --- app/code/Magento/QuoteGraphQl/composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index 05575ef371600..9d29cda3b872b 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -9,7 +9,6 @@ "magento/module-checkout": "*", "magento/module-catalog": "*", "magento/module-store": "*", - "magento/module-checkout": "*", "magento/module-customer": "*", "magento/module-authorization": "*" }, From 2095d836b5fc31dac949b37dad31fd6973fea406 Mon Sep 17 00:00:00 2001 From: Dmytro Salamatov <sal.dima27@gmail.com> Date: Tue, 6 Nov 2018 00:11:18 +0200 Subject: [PATCH 0513/1158] magento/magento2#19071: Password strength indicator shows No Password even when a password is entered --- .../view/frontend/web/js/password-strength-indicator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js index 89d9b320c049d..9742e37f2df57 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js +++ b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js @@ -83,7 +83,7 @@ define([ } else { isValid = $.validator.validateSingleElement(this.options.cache.input); zxcvbnScore = zxcvbn(password).score; - displayScore = isValid ? zxcvbnScore : 1; + displayScore = isValid && zxcvbnScore > 0 ? zxcvbnScore : 1; } } From 8aafa54f3356a8d361231cf3d84e19f80ef076c0 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Tue, 6 Nov 2018 14:41:16 -0600 Subject: [PATCH 0514/1158] ENGCOM-3368: fixed - can't import external http to https redirecting images by default csv import #18900 - Fixed docblock --- lib/internal/Magento/Framework/Filesystem/Driver/Http.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php index e43f35b072f1d..3668bd17477a4 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php @@ -12,7 +12,6 @@ /** * Class Http - * */ class Http extends File { From a58147333b285ed746a9b516d9bc6561c289010d Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Tue, 6 Nov 2018 15:15:52 -0600 Subject: [PATCH 0515/1158] MQE-1339: Bump MFTF version in Magento - MFTF version upgrade to 2.3.10 --- composer.json | 2 +- composer.lock | 168 +++++++++++++++++++++++++------------------------- 2 files changed, 85 insertions(+), 85 deletions(-) diff --git a/composer.json b/composer.json index ca345c1897412..0a2716489d6c9 100644 --- a/composer.json +++ b/composer.json @@ -84,7 +84,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "~2.13.0", "lusitanian/oauth": "~0.8.10", - "magento/magento2-functional-testing-framework": "2.3.9", + "magento/magento2-functional-testing-framework": "2.3.10", "pdepend/pdepend": "2.5.2", "phpmd/phpmd": "@stable", "phpunit/phpunit": "~6.5.0", diff --git a/composer.lock b/composer.lock index c6d14eb38bc64..ab0c8f2bf8973 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "49fe82043cd4ae944939b6cceade1d1b", + "content-hash": "52b81b57603c71ff946453178068a064", "packages": [ { "name": "braintree/braintree_php", @@ -257,16 +257,16 @@ }, { "name": "composer/composer", - "version": "1.7.2", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "576aab9b5abb2ed11a1c52353a759363216a4ad2" + "reference": "e965b9aaa8854c3067f1ed2ae45f436572d73eb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/576aab9b5abb2ed11a1c52353a759363216a4ad2", - "reference": "576aab9b5abb2ed11a1c52353a759363216a4ad2", + "url": "https://api.github.com/repos/composer/composer/zipball/e965b9aaa8854c3067f1ed2ae45f436572d73eb7", + "reference": "e965b9aaa8854c3067f1ed2ae45f436572d73eb7", "shasum": "" }, "require": { @@ -333,7 +333,7 @@ "dependency", "package" ], - "time": "2018-08-16T14:57:12+00:00" + "time": "2018-11-01T09:05:06+00:00" }, { "name": "composer/semver", @@ -399,16 +399,16 @@ }, { "name": "composer/spdx-licenses", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "cb17687e9f936acd7e7245ad3890f953770dec1b" + "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/cb17687e9f936acd7e7245ad3890f953770dec1b", - "reference": "cb17687e9f936acd7e7245ad3890f953770dec1b", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2", + "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2", "shasum": "" }, "require": { @@ -456,7 +456,7 @@ "spdx", "validator" ], - "time": "2018-04-30T10:33:04+00:00" + "time": "2018-11-01T09:45:54+00:00" }, { "name": "composer/xdebug-handler", @@ -919,16 +919,16 @@ }, { "name": "monolog/monolog", - "version": "1.23.0", + "version": "1.24.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", "shasum": "" }, "require": { @@ -993,7 +993,7 @@ "logging", "psr-3" ], - "time": "2017-06-19T01:22:40+00:00" + "time": "2018-11-05T09:00:11+00:00" }, { "name": "oyejorge/less.php", @@ -1375,16 +1375,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "2.0.11", + "version": "2.0.12", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b" + "reference": "8814dc7841db159daed0b32c2b08fb7e03c6afe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7053f06f91b3de78e143d430e55a8f7889efc08b", - "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/8814dc7841db159daed0b32c2b08fb7e03c6afe7", + "reference": "8814dc7841db159daed0b32c2b08fb7e03c6afe7", "shasum": "" }, "require": { @@ -1463,7 +1463,7 @@ "x.509", "x509" ], - "time": "2018-04-15T16:55:05+00:00" + "time": "2018-11-04T05:45:48+00:00" }, { "name": "psr/container", @@ -1834,16 +1834,16 @@ }, { "name": "symfony/console", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b" + "reference": "432122af37d8cd52fba1b294b11976e0d20df595" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/dc7122fe5f6113cfaba3b3de575d31112c9aa60b", - "reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b", + "url": "https://api.github.com/repos/symfony/console/zipball/432122af37d8cd52fba1b294b11976e0d20df595", + "reference": "432122af37d8cd52fba1b294b11976e0d20df595", "shasum": "" }, "require": { @@ -1898,20 +1898,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:15:46+00:00" + "time": "2018-10-31T09:30:44+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e" + "reference": "552541dad078c85d9414b09c041ede488b456cd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bfb30c2ad377615a463ebbc875eba64a99f6aa3e", - "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/552541dad078c85d9414b09c041ede488b456cd5", + "reference": "552541dad078c85d9414b09c041ede488b456cd5", "shasum": "" }, "require": { @@ -1961,20 +1961,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-07-26T09:10:45+00:00" + "time": "2018-10-10T13:52:42+00:00" }, { "name": "symfony/filesystem", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "596d12b40624055c300c8b619755b748ca5cf0b5" + "reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/596d12b40624055c300c8b619755b748ca5cf0b5", - "reference": "596d12b40624055c300c8b619755b748ca5cf0b5", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd7bd6535beb1f0a0a9e3ee960666d0598546981", + "reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981", "shasum": "" }, "require": { @@ -2011,11 +2011,11 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:40:59+00:00" + "time": "2018-10-30T13:18:25+00:00" }, { "name": "symfony/finder", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -2064,7 +2064,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -2122,16 +2122,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", - "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "shasum": "" }, "require": { @@ -2177,20 +2177,20 @@ "portable", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-21T13:07:52+00:00" }, { "name": "symfony/process", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "ee33c0322a8fee0855afcc11fff81e6b1011b529" + "reference": "3e83acef94d979b1de946599ef86b3a352abcdc9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/ee33c0322a8fee0855afcc11fff81e6b1011b529", - "reference": "ee33c0322a8fee0855afcc11fff81e6b1011b529", + "url": "https://api.github.com/repos/symfony/process/zipball/3e83acef94d979b1de946599ef86b3a352abcdc9", + "reference": "3e83acef94d979b1de946599ef86b3a352abcdc9", "shasum": "" }, "require": { @@ -2226,7 +2226,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:40:59+00:00" + "time": "2018-10-14T20:48:13+00:00" }, { "name": "tedivm/jshrink", @@ -6351,16 +6351,16 @@ }, { "name": "magento/magento2-functional-testing-framework", - "version": "2.3.9", + "version": "2.3.10", "source": { "type": "git", "url": "https://github.com/magento/magento2-functional-testing-framework.git", - "reference": "9885925ea741d0b0eede35be09a45b62d9ef7c84" + "reference": "7cd80dbf1af405473f1a976c3b75097a0f27725d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/9885925ea741d0b0eede35be09a45b62d9ef7c84", - "reference": "9885925ea741d0b0eede35be09a45b62d9ef7c84", + "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/7cd80dbf1af405473f1a976c3b75097a0f27725d", + "reference": "7cd80dbf1af405473f1a976c3b75097a0f27725d", "shasum": "" }, "require": { @@ -6418,7 +6418,7 @@ "magento", "testing" ], - "time": "2018-10-28T11:19:53+00:00" + "time": "2018-11-06T20:54:16+00:00" }, { "name": "moontoast/math", @@ -8228,7 +8228,7 @@ }, { "name": "symfony/browser-kit", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", @@ -8285,16 +8285,16 @@ }, { "name": "symfony/config", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96" + "reference": "991fec8bbe77367fc8b48ecbaa8a4bd6e905a238" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/b3d4d7b567d7a49e6dfafb6d4760abc921177c96", - "reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96", + "url": "https://api.github.com/repos/symfony/config/zipball/991fec8bbe77367fc8b48ecbaa8a4bd6e905a238", + "reference": "991fec8bbe77367fc8b48ecbaa8a4bd6e905a238", "shasum": "" }, "require": { @@ -8344,11 +8344,11 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-09-08T13:24:10+00:00" + "time": "2018-10-31T09:09:42+00:00" }, { "name": "symfony/css-selector", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -8401,16 +8401,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30" + "reference": "e72ee2c23d952e4c368ee98610fa22b79b89b483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f6b9d893ad28aefd8942dc0469c8397e2216fe30", - "reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e72ee2c23d952e4c368ee98610fa22b79b89b483", + "reference": "e72ee2c23d952e4c368ee98610fa22b79b89b483", "shasum": "" }, "require": { @@ -8468,11 +8468,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:40:59+00:00" + "time": "2018-10-31T10:54:16+00:00" }, { "name": "symfony/dom-crawler", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", @@ -8529,16 +8529,16 @@ }, { "name": "symfony/http-foundation", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "d528136617ff24f530e70df9605acc1b788b08d4" + "reference": "82d494c1492b0dd24bbc5c2d963fb02eb44491af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d528136617ff24f530e70df9605acc1b788b08d4", - "reference": "d528136617ff24f530e70df9605acc1b788b08d4", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/82d494c1492b0dd24bbc5c2d963fb02eb44491af", + "reference": "82d494c1492b0dd24bbc5c2d963fb02eb44491af", "shasum": "" }, "require": { @@ -8579,11 +8579,11 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:48:45+00:00" + "time": "2018-10-31T09:09:42+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", @@ -8637,16 +8637,16 @@ }, { "name": "symfony/polyfill-php70", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934" + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934", - "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", "shasum": "" }, "require": { @@ -8692,20 +8692,20 @@ "portable", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-21T06:26:08+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae" + "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/95c50420b0baed23852452a7f0c7b527303ed5ae", - "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", + "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", "shasum": "" }, "require": { @@ -8747,11 +8747,11 @@ "portable", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-21T13:07:52+00:00" }, { "name": "symfony/stopwatch", - "version": "v4.1.6", + "version": "v4.1.7", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -8800,7 +8800,7 @@ }, { "name": "symfony/yaml", - "version": "v3.4.17", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", From dda4f8af9ba60997cb7b78fcd7afe61f988b444b Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Tue, 6 Nov 2018 15:56:34 -0600 Subject: [PATCH 0516/1158] MAGETWO-95659: Fix and Unskip MTF OnePageCheckoutOfflinePaymentMethodsTest - address code review comments --- .../Test/Constraint/AssertCartIsEmpty.php | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php index 22a6136737089..cf05079b0a079 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Checkout\Test\Constraint; @@ -29,8 +30,10 @@ class AssertCartIsEmpty extends AbstractConstraint * @param BrowserInterface $browser * @return void */ - public function processAssert(CheckoutCart $checkoutCart, BrowserInterface $browser) - { + public function processAssert( + CheckoutCart $checkoutCart, + BrowserInterface $browser + ): void { $checkoutCart->open(); $cartEmptyBlock = $checkoutCart->getCartEmptyBlock(); @@ -46,7 +49,7 @@ public function processAssert(CheckoutCart $checkoutCart, BrowserInterface $brow $browser->getUrl(), true, 'Wrong link to main page on empty cart page: expected - ' . $_ENV['app_frontend_url'] - . ', actural - ' . $browser->getUrl() + . ', actual - ' . $browser->getUrl() ); } @@ -63,14 +66,18 @@ public function toString() /** * Asserts that two urls are equal * - * @param string $url1 - * @param string $url2 + * @param string $expectedUrl + * @param string $actualUrl * @param bool $ignoreScheme * @param string $message * @return void */ - private function assertUrlEqual($expectedUrl, $actualUrl, $ignoreScheme = false, $message = '') - { + private function assertUrlEqual( + string $expectedUrl, + string $actualUrl, + bool $ignoreScheme = false, + string $message = '' + ): void { $urlArray1 = parse_url($expectedUrl); $urlArray2 = parse_url($actualUrl); if ($ignoreScheme) { From cf824bcda59d97d2890b64a56a72cbb2f71e89ce Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Wed, 7 Nov 2018 12:33:59 +0400 Subject: [PATCH 0517/1158] MAGETWO-91658: Wrong Checkout Totals Sort Order in cart - Moved test from CE to EE. --- .../Test/Mftf/Data/CheckoutConfigData.xml | 25 ------ .../Mftf/Metadata/checkout_config-meta.xml | 86 ------------------- .../CheckoutTotalsSortOrderInCartTest.xml | 52 ----------- 3 files changed, 163 deletions(-) delete mode 100644 app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml delete mode 100644 app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml delete mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml b/app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml deleted file mode 100644 index bf2ae28009011..0000000000000 --- a/app/code/Magento/Checkout/Test/Mftf/Data/CheckoutConfigData.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="CheckoutShippingTotalsSortOrder" type="checkout_totals_sort_order"> - <requiredEntity type="shipping">ShippingTotalsSortOrder</requiredEntity> - </entity> - - <entity name="ShippingTotalsSortOrder" type="shipping"> - <data key="value">27</data> - </entity> - - <entity name="DefaultCheckoutTotalsSortOrder" type="default_checkout_totals_sort_order"> - <requiredEntity type="checkoutTotalFlagZero">DefaultTotalFlagZero</requiredEntity> - </entity> - <entity name="DefaultTotalFlagZero" type="checkoutTotalFlagZero"> - <data key="value">0</data> - </entity> -</entities> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml b/app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml deleted file mode 100644 index 55572ee73ac46..0000000000000 --- a/app/code/Magento/Checkout/Test/Mftf/Metadata/checkout_config-meta.xml +++ /dev/null @@ -1,86 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> - <operation name="SetCheckoutTotalsSortOrder" dataType="checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST"> - <object key="groups" dataType="checkout_totals_sort_order"> - <object key="totals_sort" dataType="checkout_totals_sort_order"> - <object key="fields" dataType="checkout_totals_sort_order"> - <object key="subtotal" dataType="subtotal"> - <field key="value">integer</field> - </object> - <object key="discount" dataType="discount"> - <field key="value">integer</field> - </object> - <object key="shipping" dataType="shipping"> - <field key="value">integer</field> - </object> - <object key="tax" dataType="tax"> - <field key="value">integer</field> - </object> - <object key="weee" dataType="weee"> - <field key="value">integer</field> - </object> - <object key="grand_total" dataType="grand_total"> - <field key="value">integer</field> - </object> - <object key="giftcardaccount" dataType="giftcardaccount"> - <field key="value">integer</field> - </object> - <object key="customerbalance" dataType="customerbalance"> - <field key="value">integer</field> - </object> - </object> - </object> - </object> - </operation> - - <operation name="DefaultCheckoutTotalsSortOrder" dataType="default_checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST"> - <object key="groups" dataType="default_checkout_totals_sort_order"> - <object key="totals_sort" dataType="default_checkout_totals_sort_order"> - <object key="fields" dataType="default_checkout_totals_sort_order"> - <object key="subtotal" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> - <field key="value">integer</field> - </object> - </object> - <object key="discount" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> - <field key="value">integer</field> - </object> - </object> - <object key="shipping" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> - <field key="value">integer</field> - </object> - </object> - <object key="tax" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> - <field key="value">integer</field> - </object> - </object> - <object key="weee" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> - <field key="value">integer</field> - </object> - </object> - <object key="grand_total" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> - <field key="value">integer</field> - </object> - </object> - <object key="giftcardaccount" dataType="giftcardaccount"> - <field key="value">integer</field> - </object> - <object key="customerbalance" dataType="customerbalance"> - <field key="value">integer</field> - </object> - </object> - </object> - </object> - </operation> -</operations> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml deleted file mode 100644 index 08623da68a8ef..0000000000000 --- a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="CheckoutTotalsSortOrderInCartTest"> - <annotations> - <title value="Checkout Totals Sort Order configuration and displaying in cart"/> - <stories value="MAGETWO-91658: Wrong Checkout Totals Sort Order in cart"/> - <description value="Checkout Totals Sort Order configuration and displaying in cart"/> - <features value="Checkout"/> - <severity value="AVERAGE"/> - <testCaseId value="MAGETWO-94944"/> - <group value="Checkout"/> - </annotations> - - <before> - <createData entity="_defaultCategory" stepKey="defaultCategory"/> - <createData entity="SimpleProduct" stepKey="simpleProduct"> - <requiredEntity createDataKey="defaultCategory"/> - </createData> - - <createData entity="ApiCartRule" stepKey="cartRule"/> - - <createData entity="CheckoutShippingTotalsSortOrder" stepKey="setConfigShippingTotalsSortOrder"/> - </before> - - <actionGroup ref="VerifyDiscountAmount" stepKey="verifyStorefront"> - <argument name="productUrl" value="$$simpleProduct.sku$$.html"/> - <argument name="quantity" value="1"/> - <argument name="expectedDiscount" value="-$61.50"/> - </actionGroup> - - <actionGroup ref="CheckTotalsSortOrderInSummarySection" stepKey="checkTotalsSortOrderInSummarySection"> - <argument name="elementName" value="Shipping (Flat Rate - Fixed)"/> - <argument name="positionNumber" value="3"/> - </actionGroup> - - <after> - <createData entity="DefaultCheckoutTotalsSortOrder" stepKey="setDefaultTotalsSortOrder"/> - - <deleteData createDataKey="cartRule" stepKey="deleteCartRule"/> - <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> - <deleteData createDataKey="defaultCategory" stepKey="deleteCategory"/> - - <magentoCLI command="cache:flush" stepKey="flushCache"/> - </after> - </test> -</tests> \ No newline at end of file From c62229f1342448ad693ae070bf57e3d819921290 Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov <isentiabov@magento.com> Date: Wed, 7 Nov 2018 12:41:13 +0200 Subject: [PATCH 0518/1158] MAGETWO-94052: CAPTCHA does not appear in "Log in" popup window - Added sleep for MTF test --- .../Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php index d951d84bab78d..d16da19cfe8b8 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php @@ -107,6 +107,7 @@ private function processLogin() if ($this->checkoutMethod === 'login') { if ($this->checkoutOnepage->getAuthenticationPopupBlock()->isVisible()) { $this->checkoutOnepage->getAuthenticationPopupBlock()->loginCustomer($this->customer); + sleep(5); $this->clickProceedToCheckoutStep->run(); } else { $this->checkoutOnepage->getLoginBlock()->loginCustomer($this->customer); From 29640f15077b1b6e75829054037b96703e5964a8 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Wed, 7 Nov 2018 13:06:46 +0200 Subject: [PATCH 0519/1158] Comparing the current block path with the current url path --- .../View/Element/Html/Link/Current.php | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php index 43bfd46c1193a..cb29c67a2ca30 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php @@ -5,6 +5,10 @@ */ namespace Magento\Framework\View\Element\Html\Link; +use Magento\Framework\App\DefaultPathInterface; +use Magento\Framework\View\Element\Template; +use Magento\Framework\View\Element\Template\Context; + /** * Block representing link with two possible states. * "Current" state means link leads to URL equivalent to URL of currently displayed page. @@ -17,25 +21,25 @@ * @method null|bool getCurrent() * @method \Magento\Framework\View\Element\Html\Link\Current setCurrent(bool $value) */ -class Current extends \Magento\Framework\View\Element\Template +class Current extends Template { /** * Default path * - * @var \Magento\Framework\App\DefaultPathInterface + * @var DefaultPathInterface */ protected $_defaultPath; /** * Constructor * - * @param \Magento\Framework\View\Element\Template\Context $context - * @param \Magento\Framework\App\DefaultPathInterface $defaultPath + * @param Context $context + * @param DefaultPathInterface $defaultPath * @param array $data */ public function __construct( - \Magento\Framework\View\Element\Template\Context $context, - \Magento\Framework\App\DefaultPathInterface $defaultPath, + Context $context, + DefaultPathInterface $defaultPath, array $data = [] ) { parent::__construct($context, $data); @@ -81,7 +85,7 @@ private function getMca() */ public function isCurrent() { - return $this->getCurrent() || $this->getUrl($this->getPath()) == $this->getUrl($this->getMca()); + return $this->getCurrent() || $this->getUrl($this->getPath()) == $this->getUrl($this->getPathInfo()); } /** @@ -147,4 +151,14 @@ private function getAttributesHtml() return $attributesHtml; } + + /** + * Get current page path info + * + * @return string + */ + private function getPathInfo() + { + return trim($this->_request->getPathInfo(), '/'); + } } From f631c90376dd2d217686e781147cc707bd816c8f Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Wed, 7 Nov 2018 14:36:22 +0200 Subject: [PATCH 0520/1158] magento/magento2#12970: [Forwardport] Can't add grouped product, with out of stock sub product, to cart. --- .../Model/Product/Type/Grouped.php | 2 +- .../_files/product_virtual_out_of_stock.php | 20 ++ .../product_virtual_out_of_stock_rollback.php | 26 +++ .../Model/Product/Type/GroupedTest.php | 194 ++++++++++++++++-- .../product_grouped_with_out_of_stock.php | 75 +++++++ ...uct_grouped_with_out_of_stock_rollback.php | 10 + 6 files changed, 311 insertions(+), 16 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php create mode 100644 dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 80824d45cb6e5..56de9ee9552ae 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -347,7 +347,7 @@ protected function getProductInfo(\Magento\Framework\DataObject $buyRequest, $pr if ($isStrictProcessMode && !$subProduct->getQty()) { return __('Please specify the quantity of product(s).')->render(); } - $productsInfo[$subProduct->getId()] = (int)$subProduct->getQty(); + $productsInfo[$subProduct->getId()] = $subProduct->isSalable() ? (float)$subProduct->getQty() : 0; } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock.php new file mode 100644 index 0000000000000..cff2e83ed002e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** @var $product \Magento\Catalog\Model\Product */ +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL) + ->setId(31) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Virtual Product Out') + ->setSku('virtual-product-out') + ->setPrice(10) + ->setTaxClassId(0) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['is_in_stock' => 0]) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock_rollback.php new file mode 100644 index 0000000000000..8055ca4a25569 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_out_of_stock_rollback.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +try { + $product = $productRepository->get('virtual-product-out', false, null, true); + $productRepository->delete($product); +} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php index dcf4565873ea5..ed283d196e69c 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php @@ -5,8 +5,19 @@ */ namespace Magento\GroupedProduct\Model\Product\Type; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\CatalogInventory\Model\Configuration; +use Magento\Framework\App\Config\ReinitableConfigInterface; +use Magento\Framework\App\Config\Value; + class GroupedTest extends \PHPUnit\Framework\TestCase { + /** + * @var ReinitableConfigInterface + */ + private $reinitableConfig; + /** * @var \Magento\Framework\ObjectManagerInterface */ @@ -20,16 +31,21 @@ class GroupedTest extends \PHPUnit\Framework\TestCase protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->_productType = $this->objectManager->get(\Magento\Catalog\Model\Product\Type::class); + $this->reinitableConfig = $this->objectManager->get(ReinitableConfigInterface::class); + } + + protected function tearDown() + { + $this->dropConfigValue(Configuration::XML_PATH_SHOW_OUT_OF_STOCK); } public function testFactory() { $product = new \Magento\Framework\DataObject(); - $product->setTypeId(\Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE); + $product->setTypeId(Grouped::TYPE_CODE); $type = $this->_productType->factory($product); - $this->assertInstanceOf(\Magento\GroupedProduct\Model\Product\Type\Grouped::class, $type); + $this->assertInstanceOf(Grouped::class, $type); } /** @@ -38,12 +54,12 @@ public function testFactory() */ public function testGetAssociatedProducts() { - $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); - /** @var \Magento\Catalog\Model\Product $product */ + /** @var Product $product */ $product = $productRepository->get('grouped-product'); $type = $product->getTypeInstance(); - $this->assertInstanceOf(\Magento\GroupedProduct\Model\Product\Type\Grouped::class, $type); + $this->assertInstanceOf(Grouped::class, $type); $associatedProducts = $type->getAssociatedProducts($product); $this->assertCount(2, $associatedProducts); @@ -53,7 +69,7 @@ public function testGetAssociatedProducts() } /** - * @param \Magento\Catalog\Model\Product $product + * @param Product $product */ private function assertProductInfo($product) { @@ -92,25 +108,25 @@ public function testPrepareProduct() \Magento\Framework\DataObject::class, ['data' => ['value' => ['qty' => 2]]] ); - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); $product = $productRepository->get('grouped-product'); - /** @var \Magento\GroupedProduct\Model\Product\Type\Grouped $type */ - $type = $this->objectManager->get(\Magento\GroupedProduct\Model\Product\Type\Grouped::class); + /** @var Grouped $type */ + $type = $this->objectManager->get(Grouped::class); $processModes = [ - \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_FULL, - \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_LITE + Grouped::PROCESS_MODE_FULL, + Grouped::PROCESS_MODE_LITE ]; $expectedData = [ - \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_FULL => [ + Grouped::PROCESS_MODE_FULL => [ 1 => '{"super_product_config":{"product_type":"grouped","product_id":"' . $product->getId() . '"}}', 21 => '{"super_product_config":{"product_type":"grouped","product_id":"' . $product->getId() . '"}}', ], - \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_LITE => [ + Grouped::PROCESS_MODE_LITE => [ $product->getId() => '{"value":{"qty":2}}', ] ]; @@ -127,4 +143,152 @@ public function testPrepareProduct() } } } + + /** + * Test adding grouped product to cart when one of subproducts is out of stock. + * + * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php + * @magentoAppArea frontend + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @dataProvider outOfStockSubProductDataProvider + * @param bool $outOfStockShown + * @param array $data + * @param array $expected + */ + public function testOutOfStockSubProduct(bool $outOfStockShown, array $data, array $expected) + { + $this->changeConfigValue(Configuration::XML_PATH_SHOW_OUT_OF_STOCK, $outOfStockShown); + $buyRequest = new \Magento\Framework\DataObject($data); + $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + /** @var Product $product */ + $product = $productRepository->get('grouped-product'); + /** @var Grouped $groupedProduct */ + $groupedProduct = $this->objectManager->get(Grouped::class); + $actual = $groupedProduct->prepareForCartAdvanced($buyRequest, $product, Grouped::PROCESS_MODE_FULL); + self::assertEquals( + count($expected), + count($actual) + ); + /** @var Product $product */ + foreach ($actual as $product) { + $sku = $product->getSku(); + self::assertEquals( + $expected[$sku], + $product->getCartQty(), + "Failed asserting that Product Cart Quantity matches expected" + ); + } + } + + /** + * Data provider for testOutOfStockSubProduct. + * + * @return array + */ + public function outOfStockSubProductDataProvider() + { + return [ + 'Out of stock product are shown #1' => [ + true, + [ + 'product' => 3, + 'qty' => 1, + 'super_group' => [ + 1 => 4, + 21 => 5, + ], + ], + [ + 'virtual-product' => 5, + 'simple' => 4 + ], + ], + 'Out of stock product are shown #2' => [ + true, + [ + 'product' => 3, + 'qty' => 1, + 'super_group' => [ + 1 => 0, + ], + ], + [ + 'virtual-product' => 2.5, // This is a default quantity. + ], + ], + 'Out of stock product are hidden #1' => [ + false, + [ + 'product' => 3, + 'qty' => 1, + 'super_group' => [ + 1 => 4, + 21 => 5, + ], + ], + [ + 'virtual-product' => 5, + 'simple' => 4, + ], + ], + 'Out of stock product are hidden #2' => [ + false, + [ + 'product' => 3, + 'qty' => 1, + 'super_group' => [ + 1 => 0, + ], + ], + [ + 'virtual-product' => 2.5, // This is a default quantity. + ], + ], + ]; + } + + /** + * Write config value to database. + * + * @param string $path + * @param string $value + * @param string $scope + * @param int $scopeId + */ + private function changeConfigValue(string $path, string $value, string $scope = 'default', int $scopeId = 0) + { + $configValue = $this->objectManager->create(Value::class); + $configValue->setPath($path) + ->setValue($value) + ->setScope($scope) + ->setScopeId($scopeId) + ->save(); + $this->reinitConfig(); + } + + /** + * Delete config value from database. + * + * @param string $path + */ + private function dropConfigValue(string $path) + { + $configValue = $this->objectManager->create(Value::class); + try { + $configValue->load($path, 'path'); + $configValue->delete(); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + // do nothing + } + $this->reinitConfig(); + } + + /** + * Reinit config. + */ + private function reinitConfig() + { + $this->reinitableConfig->reinit(); + } } diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php new file mode 100644 index 0000000000000..7aa62b149b8c0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php @@ -0,0 +1,75 @@ +\<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_associated.php'; +require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_virtual_in_stock.php'; +require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_virtual_out_of_stock.php'; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId( + \Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE +)->setAttributeSetId( + 4 +)->setWebsiteIds( + [1] +)->setName( + 'Grouped Product' +)->setSku( + 'grouped-product' +)->setPrice( + 100 +)->setTaxClassId( + 0 +)->setVisibility( + \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH +)->setStatus( + \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED +); + +$newLinks = []; +$productLinkFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory::class); + +/** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */ +$productLink = $productLinkFactory->create(); +$linkedProduct = $productRepository->getById(1); +$productLink->setSku($product->getSku()) + ->setLinkType('associated') + ->setLinkedProductSku($linkedProduct->getSku()) + ->setLinkedProductType($linkedProduct->getTypeId()) + ->setPosition(1) + ->getExtensionAttributes() + ->setQty(1); +$newLinks[] = $productLink; + +$subProductsSkus = ['virtual-product', 'virtual-product-out']; +foreach ($subProductsSkus as $sku) { + /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */ + $productLink = $productLinkFactory->create(); + $linkedProduct = $productRepository->get($sku); + $productLink->setSku($product->getSku()) + ->setLinkType('associated') + ->setLinkedProductSku($sku) + ->setLinkedProductType($linkedProduct->getTypeId()) + ->getExtensionAttributes() + ->setQty(2.5); + $newLinks[] = $productLink; +} +$product->setProductLinks($newLinks); +$product->save(); + +/** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ +$categoryLinkManagement = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\CategoryLinkManagementInterface::class); + +$categoryLinkManagement->assignProductToCategories( + $product->getSku(), + [2] +); diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php new file mode 100644 index 0000000000000..48e7d495f8985 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php @@ -0,0 +1,10 @@ +\<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require 'product_grouped_rollback.php'; +require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_virtual_out_of_stock_rollback.php'; +require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_virtual_in_stock_rollback.php'; +require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_associated_rollback.php'; From b545997c49beec86291b4a28741c43d01c53c41e Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Wed, 7 Nov 2018 15:14:20 +0200 Subject: [PATCH 0521/1158] magento/magento2#18990: Shipping address is not validated in checkout when proceeding step as logged in user with default shipping address --- .../view/frontend/web/js/view/shipping.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js index 6ac805f72f78d..c811d3a1e8369 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -266,9 +266,8 @@ define([ loginFormSelector = 'form[data-role=email-with-possible-login]', emailValidationResult = customer.isLoggedIn(), field, - countryIndexedOptions = registry.get( - this.parentName + '.shippingAddress.shipping-address-fieldset.country_id' - ).indexedOptions, + country = registry.get(this.parentName + '.shippingAddress.shipping-address-fieldset.country_id'), + countryIndexedOptions = country.indexedOptions, option = countryIndexedOptions[quote.shippingAddress().countryId], messageContainer = registry.get('checkout.errors').messageContainer; @@ -323,12 +322,14 @@ define([ shippingAddress['save_in_address_book'] = 1; } selectShippingAddress(shippingAddress); - } else if (customer.isLoggedIn() - && option - && option['is_region_required'] - && !quote.shippingAddress().region + } else if (customer.isLoggedIn() && + option && + option['is_region_required'] && + !quote.shippingAddress().region ) { - messageContainer.addErrorMessage({message: $t('Please specify a regionId in shipping address.')}); + messageContainer.addErrorMessage({ + message: $t('Please specify a regionId in shipping address.') + }); return false; } From 2cab212809680085450836442c9346130c1f6440 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Wed, 7 Nov 2018 16:02:31 +0200 Subject: [PATCH 0522/1158] Covering the \Magento\Weee\Observer\AddPaymentWeeeItem by Unit Test --- .../Unit/Observer/AddPaymentWeeeItemTest.php | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php diff --git a/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php b/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php new file mode 100644 index 0000000000000..1e707b118dccb --- /dev/null +++ b/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php @@ -0,0 +1,154 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Weee\Test\Unit\Observer; + +use Magento\Framework\Event; +use Magento\Framework\Event\Observer; +use Magento\Payment\Model\Cart; +use Magento\Payment\Model\Cart\SalesModel\SalesModelInterface; +use Magento\Quote\Model\Quote\Item; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Weee\Helper\Data; +use Magento\Weee\Observer\AddPaymentWeeeItem; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +/** + * Class AddPaymentWeeeItemTest + */ +class AddPaymentWeeeItemTest extends TestCase +{ + /** + * Testable object + * + * @var AddPaymentWeeeItem + */ + private $observer; + + /** + * @var Data|MockObject + */ + private $weeeHelperMock; + + /** + * @var StoreManagerInterface|MockObject + */ + private $storeManagerMock; + + /** + * Set Up + */ + protected function setUp() + { + $this->weeeHelperMock = $this->createMock(Data::class); + $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); + + $this->observer = new AddPaymentWeeeItem( + $this->weeeHelperMock, + $this->storeManagerMock + ); + } + + /** + * Test execute + * + * @dataProvider dataProvider + * @param $isEnabled + * @param $includeInSubtotal + * @return void + */ + public function testExecute($isEnabled, $includeInSubtotal): void + { + /** @var Observer|MockObject $observerMock */ + $observerMock = $this->createMock(Observer::class); + $cartModelMock = $this->createMock(Cart::class); + $salesModelMock = $this->createMock(SalesModelInterface::class); + $itemMock = $this->createPartialMock(Item::class, ['getOriginalItem']); + $originalItemMock = $this->createPartialMock(Item::class, ['getParentItem']); + $parentItemMock = $this->createMock(Item::class); + $eventMock = $this->getMockBuilder(Event::class) + ->disableOriginalConstructor() + ->setMethods(['getCart']) + ->getMock(); + + $asCustomItem = $this->prepareShouldBeAddedAsCustomItem($isEnabled, $includeInSubtotal); + $toBeCalled = 1; + if (!$asCustomItem) { + $toBeCalled = 0; + } + + $eventMock->expects($this->exactly($toBeCalled)) + ->method('getCart') + ->willReturn($cartModelMock); + $observerMock->expects($this->exactly($toBeCalled)) + ->method('getEvent') + ->willReturn($eventMock); + $itemMock->expects($this->exactly($toBeCalled)) + ->method('getOriginalItem') + ->willReturn($originalItemMock); + $originalItemMock->expects($this->exactly($toBeCalled)) + ->method('getParentItem') + ->willReturn($parentItemMock); + $salesModelMock->expects($this->exactly($toBeCalled)) + ->method('getAllItems') + ->willReturn([$itemMock]); + $cartModelMock->expects($this->exactly($toBeCalled)) + ->method('getSalesModel') + ->willReturn($salesModelMock); + + $this->observer->execute($observerMock); + } + + /** + * @return array + */ + public function dataProvider(): array + { + return [ + [true, false], + [true, true], + [false, true], + [false, false], + ]; + } + + /** + * Prepare if FPT should be added to payment cart as custom item or not. + * + * @param $isEnabled + * @param $includeInSubtotal + * @return bool + */ + private function prepareShouldBeAddedAsCustomItem(bool $isEnabled, bool $includeInSubtotal): bool + { + $storeMock = $this->getMockBuilder(StoreInterface::class) + ->setMethods(['getId']) + ->getMockForAbstractClass(); + $storeMock->expects($this->once()) + ->method('getId') + ->willReturn(Store::DEFAULT_STORE_ID); + $this->storeManagerMock->expects($this->once()) + ->method('getStore') + ->willReturn($storeMock); + $this->weeeHelperMock->expects($this->once()) + ->method('isEnabled') + ->with(Store::DEFAULT_STORE_ID) + ->willReturn($isEnabled); + + if ($isEnabled) { + $this->weeeHelperMock->expects($this->once()) + ->method('includeInSubtotal') + ->with(Store::DEFAULT_STORE_ID) + ->willReturn($includeInSubtotal); + } + + return $isEnabled && !$includeInSubtotal; + } +} From bb20a8b757ca43f16b63e98dd97aa5c6f630eaa0 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Wed, 7 Nov 2018 16:45:52 +0200 Subject: [PATCH 0523/1158] Small refactoring. Covering the SetWeeeRendererInFormObserver class by Unit Test --- .../Unit/Observer/AddPaymentWeeeItemTest.php | 10 +-- .../SetWeeeRendererInFormObserverTest.php | 88 +++++++++++++++++++ 2 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 app/code/Magento/Weee/Test/Unit/Observer/SetWeeeRendererInFormObserverTest.php diff --git a/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php b/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php index 1e707b118dccb..dd0547354cfa4 100644 --- a/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php +++ b/app/code/Magento/Weee/Test/Unit/Observer/AddPaymentWeeeItemTest.php @@ -60,11 +60,11 @@ protected function setUp() * Test execute * * @dataProvider dataProvider - * @param $isEnabled - * @param $includeInSubtotal + * @param bool $isEnabled + * @param bool $includeInSubtotal * @return void */ - public function testExecute($isEnabled, $includeInSubtotal): void + public function testExecute(bool $isEnabled, bool $includeInSubtotal): void { /** @var Observer|MockObject $observerMock */ $observerMock = $this->createMock(Observer::class); @@ -122,8 +122,8 @@ public function dataProvider(): array /** * Prepare if FPT should be added to payment cart as custom item or not. * - * @param $isEnabled - * @param $includeInSubtotal + * @param bool $isEnabled + * @param bool $includeInSubtotal * @return bool */ private function prepareShouldBeAddedAsCustomItem(bool $isEnabled, bool $includeInSubtotal): bool diff --git a/app/code/Magento/Weee/Test/Unit/Observer/SetWeeeRendererInFormObserverTest.php b/app/code/Magento/Weee/Test/Unit/Observer/SetWeeeRendererInFormObserverTest.php new file mode 100644 index 0000000000000..188b42cb37906 --- /dev/null +++ b/app/code/Magento/Weee/Test/Unit/Observer/SetWeeeRendererInFormObserverTest.php @@ -0,0 +1,88 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Weee\Test\Unit\Observer; + +use Magento\Framework\Data\Form; +use Magento\Framework\Event; +use Magento\Framework\Event\Observer; +use Magento\Framework\View\LayoutInterface; +use Magento\Weee\Model\Tax; +use Magento\Weee\Observer\SetWeeeRendererInFormObserver; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +/** + * Class AddPaymentWeeeItemTest + */ +class SetWeeeRendererInFormObserverTest extends TestCase +{ + /** + * Testable object + * + * @var SetWeeeRendererInFormObserver + */ + private $observer; + + /** + * @var LayoutInterface|MockObject + */ + private $layoutMock; + + /** + * @var Tax|MockObject + */ + private $taxModelMock; + + /** + * Set Up + */ + protected function setUp() + { + $this->layoutMock = $this->createMock(LayoutInterface::class); + $this->taxModelMock = $this->createMock(Tax::class); + $this->observer = new SetWeeeRendererInFormObserver( + $this->layoutMock, + $this->taxModelMock + ); + } + + /** + * Test assigning a custom renderer for product create/edit form weee attribute element + * + * @return void + */ + public function testExecute(): void + { + $attributes = new \ArrayIterator(['element_code_1', 'element_code_2']); + /** @var Event|MockObject $eventMock */ + $eventMock = $this->getMockBuilder(Event::class) + ->disableOriginalConstructor() + ->setMethods(['getForm']) + ->getMock(); + + /** @var Observer|MockObject $observerMock */ + $observerMock = $this->createMock(Observer::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + + $eventMock->expects($this->once()) + ->method('getForm') + ->willReturn($formMock); + $observerMock->expects($this->once()) + ->method('getEvent') + ->willReturn($eventMock); + $this->taxModelMock->expects($this->once()) + ->method('getWeeeAttributeCodes') + ->willReturn($attributes); + $formMock->expects($this->exactly($attributes->count())) + ->method('getElement') + ->willReturnSelf(); + + $this->observer->execute($observerMock); + } +} From 965de969e224387fa307c7f8c099a25d78c4f5a4 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Wed, 7 Nov 2018 16:48:13 +0200 Subject: [PATCH 0524/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add json response to save address action; --- .../Controller/Adminhtml/Address/Save.php | 69 ++++++++++++------- .../Customer/Model/Address/DataProvider.php | 27 ++++---- .../web/js/address/default-address.js | 16 ++--- 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 8b70263d3f95b..3bd49d038588c 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -8,7 +8,10 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Controller\ResultInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Psr\Log\LoggerInterface; /** @@ -53,6 +56,11 @@ class Save extends Action implements HttpPostActionInterface */ private $logger; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + /** * @param Action\Context $context * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository @@ -61,6 +69,7 @@ class Save extends Action implements HttpPostActionInterface * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper * @param \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory * @param LoggerInterface $logger + * @param JsonFactory $resultJsonFactory */ public function __construct( Action\Context $context, @@ -69,7 +78,8 @@ public function __construct( \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory, - LoggerInterface $logger + LoggerInterface $logger, + JsonFactory $resultJsonFactory ) { parent::__construct($context); $this->addressRepository = $addressRepository; @@ -78,23 +88,24 @@ public function __construct( $this->dataObjectHelper = $dataObjectHelper; $this->addressDataFactory = $addressDataFactory; $this->logger = $logger; + $this->resultJsonFactory = $resultJsonFactory; } /** * Save customer address action * - * @return \Magento\Framework\Controller\Result\Redirect - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Magento\Framework\Exception\NoSuchEntityException + * @return ResultInterface */ - public function execute(): Redirect + public function execute(): ResultInterface { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('entity_id', false); - /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ - $customer = $this->customerRepository->getById($customerId); + $error = false; try { + /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ + $customer = $this->customerRepository->getById($customerId); + $addressForm = $this->formFactory->create( 'customer_address', 'adminhtml_customer_address', @@ -124,29 +135,39 @@ public function execute(): Redirect ); if ($addressId) { $addressToSave->setId($addressId); - $saveMessage = __('Customer address has been updated.'); + $message = __('Customer address has been updated.'); } else { $addressToSave->setId(null); - $saveMessage = __('New customer address has been added.'); + $message = __('New customer address has been added.'); } - - $this->addressRepository->save($addressToSave); - $this->messageManager->addSuccessMessage($saveMessage); - } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addErrorMessage($e->getMessage()); + $savedAddress = $this->addressRepository->save($addressToSave); + $addressId = $savedAddress->getId(); + } catch (NoSuchEntityException $e) { + $this->logger->critical($e); + $error = true; + $message = __('There is no customer with such id.'); + } catch (LocalizedException $e) { + $error = true; + $message = __($e->getMessage()); $this->logger->critical($e); } catch (\Exception $e) { - $this->messageManager->addExceptionMessage( - $e, - __('We can\'t change customer address right now.') - ); + $error = true; + $message = __('We can\'t change customer address right now.'); + $this->logger->critical($e); } - $resultRedirect = $this->resultRedirectFactory->create(); - $resultRedirect->setPath( - 'customer/index/edit', - ['id' => $customerId, '_current' => true] + $addressId = empty($addressId) ? null : $addressId; + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + 'data' => [ + 'addressId' => $addressId + ] + ] ); - return $resultRedirect; + + return $resultJson; } } diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 1b4bcf94fec15..a7c0da08324d3 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -126,21 +126,18 @@ public function getData(): array if (null !== $this->loadedData) { return $this->loadedData; } - $items = $this->collection->getItems(); - /** @var Address $item */ - foreach ($items as $item) { - $addressId = $item->getEntityId(); - $item->load($addressId); - $this->loadedData[$addressId] = $item->getData(); - $customerId = $this->loadedData[$addressId]['parent_id']; - /** @var \Magento\Customer\Model\Customer $customer */ - $customer = $this->customerRepository->getById($customerId); - $defaultBilling = $customer->getDefaultBilling(); - $defaultShipping = $customer->getDefaultShipping(); - $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); - - $this->fileUploaderDataResolver->overrideFileUploaderData($item, $this->loadedData[$addressId]); - } + /** @var Address $address */ + $address = $this->collection->getFirstItem(); + $addressId = $address->getEntityId(); + $address->load($addressId); + $this->loadedData[$addressId] = $address->getData(); + $customerId = $this->loadedData[$addressId]['parent_id']; + /** @var \Magento\Customer\Model\Customer $customer */ + $customer = $this->customerRepository->getById($customerId); + $defaultBilling = $customer->getDefaultBilling(); + $defaultShipping = $customer->getDefaultShipping(); + $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); + $this->fileUploaderDataResolver->overrideFileUploaderData($address, $this->loadedData[$addressId]); if (null === $this->loadedData) { $this->loadedData[''] = $this->getDefaultData(); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index 530df8544c841..b4ec734cb4033 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -10,8 +10,8 @@ define([ return Button.extend({ defaults: { - entityId: null, - parentId: null + entity_id: null, + parent_id: null }, /** @@ -21,8 +21,8 @@ define([ */ initialize: function () { this._super(); - if (!this.parentId) { - this.visible(this.entityId); + if (!this.parent_id) { + this.visible(this.entity_id); } return this; @@ -36,12 +36,12 @@ define([ */ applyAction: function (action) { if (action.params && action.params[0]) { - action.params[0].entityId = this.entityId; - action.params[0].parentId = this.parentId; + action.params[0].entity_id = this.entity_id; + action.params[0].parent_id = this.parent_id; } else { action.params = [{ - entityId: this.entityId, - parentId: this.parentId + entity_id: this.entity_id, + parent_id: this.parent_id }]; } From 773746968337a08d5f89f5a09113dd763bc0577f Mon Sep 17 00:00:00 2001 From: Stanislav Idolov <sidolov@magento.com> Date: Wed, 7 Nov 2018 17:18:24 +0200 Subject: [PATCH 0525/1158] magento-engcom/magento2ce#2316: Code style fixes --- app/code/Magento/Catalog/Model/Design.php | 5 +++-- lib/internal/Magento/Framework/Translate.php | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Design.php b/app/code/Magento/Catalog/Model/Design.php index 6c0629feaf6fd..853bbeac8eb38 100644 --- a/app/code/Magento/Catalog/Model/Design.php +++ b/app/code/Magento/Catalog/Model/Design.php @@ -43,9 +43,10 @@ class Design extends \Magento\Framework\Model\AbstractModel * @param \Magento\Framework\Registry $registry * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate * @param \Magento\Framework\View\DesignInterface $design - * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource - * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection + * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource + * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection * @param array $data + * @param TranslateInterface|null $translator */ public function __construct( \Magento\Framework\Model\Context $context, diff --git a/lib/internal/Magento/Framework/Translate.php b/lib/internal/Magento/Framework/Translate.php index ff1bf99162a8a..f889549a107a8 100644 --- a/lib/internal/Magento/Framework/Translate.php +++ b/lib/internal/Magento/Framework/Translate.php @@ -278,6 +278,7 @@ protected function getConfig($key) /** * Retrieve name of the current module + * * @return mixed */ protected function getControllerModuleName() From 7c6ecc33bf6d5707021548e0920650b7feec265c Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov <isentiabov@magento.com> Date: Wed, 7 Nov 2018 17:27:01 +0200 Subject: [PATCH 0526/1158] MAGETWO-70532: [GitHub] REST API Missing Product_Option values for Order Items in salesOrderManagementV1 and salesOrderItemRepositoryV1 #9326 - Added product options merger --- app/code/Magento/Sales/Model/Order/ItemRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index e9764e7d38c5a..d7dc0ca67d81c 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -168,7 +168,9 @@ public function save(OrderItemInterface $entity) { if ($entity->getProductOption()) { $request = $this->getBuyRequest($entity); - $entity->setProductOptions(['info_buyRequest' => $request->toArray()]); + $productOptions = $entity->getProductOptions(); + $productOptions['info_buyRequest'] = $request->toArray(); + $entity->setProductOptions($productOptions); } $this->metadata->getMapper()->save($entity); From d7fca7216491ac404b00ca6ff43d0ac6751a5597 Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Tue, 6 Nov 2018 19:26:30 -0600 Subject: [PATCH 0527/1158] MAGETWO-95745: Signifyd case not created for WorldPay - revert MAGETWO-94269 --- .../Paypal/Controller/Payflow/ReturnUrl.php | 4 ++-- .../Unit/Controller/Payflow/ReturnUrlTest.php | 16 ---------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php b/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php index 56a5da40edb85..cf932f046d1be 100644 --- a/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php +++ b/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php @@ -6,6 +6,7 @@ */ namespace Magento\Paypal\Controller\Payflow; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\CsrfAwareActionInterface; use Magento\Framework\App\Request\InvalidRequestException; use Magento\Framework\App\RequestInterface; @@ -13,7 +14,7 @@ use Magento\Paypal\Model\Config; use Magento\Sales\Model\Order; -class ReturnUrl extends Payflow implements CsrfAwareActionInterface +class ReturnUrl extends Payflow implements CsrfAwareActionInterface, HttpGetActionInterface { /** * @var array of allowed order states on frontend @@ -68,7 +69,6 @@ public function execute() if ($order->getIncrementId()) { if ($this->checkOrderState($order)) { $redirectBlock->setData('goto_success_page', true); - $this->_eventManager->dispatch('paypal_checkout_success', ['order' => $order]); } else { if ($this->checkPaymentMethod($order)) { $gotoSection = $this->_cancelPayment((string)$this->getRequest()->getParam('RESPMSG')); diff --git a/app/code/Magento/Paypal/Test/Unit/Controller/Payflow/ReturnUrlTest.php b/app/code/Magento/Paypal/Test/Unit/Controller/Payflow/ReturnUrlTest.php index 44775d7e381bb..32d3f2c73b159 100644 --- a/app/code/Magento/Paypal/Test/Unit/Controller/Payflow/ReturnUrlTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Controller/Payflow/ReturnUrlTest.php @@ -5,7 +5,6 @@ */ namespace Magento\Paypal\Test\Unit\Controller\Payflow; -use Magento\Framework\Event\ManagerInterface; use Magento\Sales\Api\PaymentFailuresInterface; use Magento\Checkout\Block\Onepage\Success; use Magento\Checkout\Model\Session; @@ -97,11 +96,6 @@ class ReturnUrlTest extends \PHPUnit\Framework\TestCase */ private $paymentFailures; - /** - * @var ManagerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $eventManagerMock; - /** * @inheritdoc */ @@ -158,16 +152,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->eventManagerMock = $this->getMockBuilder(ManagerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->context->method('getView') ->willReturn($this->view); $this->context->method('getRequest') ->willReturn($this->request); - $this->context->method('getEventManager') - ->willReturn($this->eventManagerMock); $this->returnUrl = $this->objectManager->getObject( ReturnUrl::class, @@ -199,10 +187,6 @@ public function testExecuteAllowedOrderState($state) ->with('goto_success_page', true) ->willReturnSelf(); - $this->eventManagerMock->expects($this->once()) - ->method('dispatch') - ->with('paypal_checkout_success', $this->arrayHasKey('order')); - $result = $this->returnUrl->execute(); $this->assertNull($result); } From 385b01ef801cfa5fc5e2745bd71154bee85f8c3b Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Wed, 7 Nov 2018 10:58:54 -0600 Subject: [PATCH 0528/1158] MAGETWO-95745: Signifyd case not created for WorldPay - revert MAGETWO-71763 --- app/code/Magento/Signifyd/etc/events.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Signifyd/etc/events.xml b/app/code/Magento/Signifyd/etc/events.xml index e6418e2fdb6b4..d44665f9fb97b 100644 --- a/app/code/Magento/Signifyd/etc/events.xml +++ b/app/code/Magento/Signifyd/etc/events.xml @@ -9,9 +9,6 @@ <event name="checkout_submit_all_after"> <observer name="signifyd_place_order_observer" instance="Magento\Signifyd\Observer\PlaceOrder" /> </event> - <event name="paypal_express_place_order_success"> - <observer name="signifyd_place_order_paypal_express_observer" instance="Magento\Signifyd\Observer\PlaceOrder"/> - </event> <event name="paypal_checkout_success"> <observer name="signifyd_place_order_checkout_success_observer" instance="Magento\Signifyd\Observer\PlaceOrder" /> </event> From 436f0d995df9c0a374ec504f4302d2bf6e909af5 Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Wed, 7 Nov 2018 11:32:54 -0600 Subject: [PATCH 0529/1158] MAGETWO-95745: Signifyd case not created for WorldPay - fix static test failures --- app/code/Magento/Checkout/Controller/Onepage/Success.php | 4 +++- app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/Controller/Onepage/Success.php b/app/code/Magento/Checkout/Controller/Onepage/Success.php index e0872b425cc7c..a657b23cca4d6 100644 --- a/app/code/Magento/Checkout/Controller/Onepage/Success.php +++ b/app/code/Magento/Checkout/Controller/Onepage/Success.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -8,6 +7,9 @@ use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; +/** + * Onepage checkout success controller class + */ class Success extends \Magento\Checkout\Controller\Onepage implements HttpGetActionInterface { /** diff --git a/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php b/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php index cf932f046d1be..d2a14febe54dd 100644 --- a/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php +++ b/app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -14,6 +13,9 @@ use Magento\Paypal\Model\Config; use Magento\Sales\Model\Order; +/** + * Paypal Payflow ReturnUrl controller class + */ class ReturnUrl extends Payflow implements CsrfAwareActionInterface, HttpGetActionInterface { /** From 240cfb3e8b2ed77cf63566d7326e537771e8bceb Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Wed, 7 Nov 2018 20:35:18 +0200 Subject: [PATCH 0530/1158] graphQl: fixed typos and wrong descriptions --- .../QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php | 8 ++++---- .../Model/Cart/SetShippingAddressesOnCartInterface.php | 3 ++- app/code/Magento/QuoteGraphQl/etc/schema.graphqls | 3 +-- .../GraphQl/Quote/SetShippingAddressOnCartTest.php | 9 ++++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php index 588d4f65cc565..960900682db4c 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressOnCart.php @@ -59,7 +59,7 @@ public function execute(ContextInterface $context, CartInterface $cart, array $s { if (count($shippingAddresses) > 1) { throw new GraphQlInputException( - __('Multiple addresses do not allowed here!') + __('You cannot specify multiple shipping addresses.') ); } $shippingAddress = current($shippingAddresses); @@ -68,19 +68,19 @@ public function execute(ContextInterface $context, CartInterface $cart, array $s if (!$customerAddressId && !$addressInput) { throw new GraphQlInputException( - __('Shipping address should contain either "customer_address_id" or "address" input.') + __('The shipping address must contain either "customer_address_id" or "address".') ); } if ($customerAddressId && $addressInput) { throw new GraphQlInputException( - __('Shipping address can\'t contain "customer_address_id" and "address" input at the same time.') + __('The shipping address cannot contain "customer_address_id" and "address" at the same time.') ); } if ($customerAddressId) { if ((!$context->getUserId()) || $context->getUserType() == UserContextInterface::USER_TYPE_GUEST) { throw new GraphQlAuthorizationException( __( - 'Address management allowed only for authorized customers.' + 'Guest users cannot manage addresses.' ) ); } diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php index ae337240c3a26..dde9cce9d8693 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCartInterface.php @@ -14,7 +14,8 @@ /** * Extension point for setting shipping addresses for a specified shopping cart * - * All objects that are responsible for set shipping addresses on cart via GraphQl should implement this interface. + * All objects that are responsible for setting shipping addresses on a cart via GraphQl + *should implement this interface. */ interface SetShippingAddressesOnCartInterface { diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 017b1f8119829..15d90c352ba62 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -6,11 +6,10 @@ type Query { } type Mutation { - createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") + createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates an empty shopping cart for a guest or logged in user") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingAddressesOnCart") - createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveCouponFromCart") setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php index 48ef8ebb790d1..2b4223cf67a89 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingAddressOnCartTest.php @@ -139,13 +139,12 @@ public function testSetSavedShippingAddressOnCartByGuest() } } QUERY; - self::expectExceptionMessage('Address management allowed only for authorized customers.'); + self::expectExceptionMessage('Guest users cannot manage addresses.'); $this->graphQlQuery($query); } /** * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php - * @magentoConfigFixture default_store multishipping/options/checkout_multiple 0 */ public function testSetMultipleShippingAddressesOnCartByGuest() { @@ -185,7 +184,7 @@ public function testSetMultipleShippingAddressesOnCartByGuest() } } QUERY; - self::expectExceptionMessage('Multiple addresses do not allowed here!'); + self::expectExceptionMessage('You cannot specify multiple shipping addresses.'); $this->graphQlQuery($query); } @@ -240,7 +239,7 @@ public function testSetSavedAndNewShippingAddressOnCartAtTheSameTime() } QUERY; self::expectExceptionMessage( - 'Shipping address can\'t contain "customer_address_id" and "address" input at the same time.' + 'The shipping address cannot contain "customer_address_id" and "address" at the same time.' ); $this->graphQlQuery($query); } @@ -282,7 +281,7 @@ public function testSetShippingAddressOnCartWithNoAddresses() } QUERY; self::expectExceptionMessage( - 'Shipping address should contain either "customer_address_id" or "address" input.' + 'The shipping address must contain either "customer_address_id" or "address".' ); $this->graphQlQuery($query); } From b490fb16a0e21eb4b11327d4dcc2e54ebdfdaca4 Mon Sep 17 00:00:00 2001 From: larsroettig <l.roettig@techdivision.com> Date: Wed, 7 Nov 2018 20:35:28 +0100 Subject: [PATCH 0531/1158] #18956 Add TestCase for no root_category_id set --- .../Config/Importer/Processor/CreateTest.php | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php b/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php index 0901464224399..0fbf7bb7f044b 100644 --- a/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/Config/Importer/Processor/CreateTest.php @@ -196,14 +196,30 @@ private function initTestData() 'root_category_id' => '1', 'default_store_id' => '1', 'code' => 'default', + ], + 2 => [ + 'group_id' => '1', + 'website_id' => '1', + 'name' => 'Default1', + 'default_store_id' => '1', + 'code' => 'default1', ] ]; - $this->trimmedGroup = [ - 'name' => 'Default', - 'root_category_id' => '1', - 'code' => 'default', - 'default_store_id' => '1', - ]; + $this->trimmedGroup = + [ + 0 => [ + 'name' => 'Default', + 'root_category_id' => '1', + 'code' => 'default', + 'default_store_id' => '1', + ], + 1 => [ + 'name' => 'Default1', + 'root_category_id' => '0', + 'code' => 'default1', + 'default_store_id' => '1' + ] + ]; $this->stores = [ 'default' => [ 'store_id' => '1', @@ -280,31 +296,34 @@ public function testRunGroup() [ScopeInterface::SCOPE_GROUPS, $this->groups, $this->groups], ]); - $this->websiteMock->expects($this->once()) + $this->websiteMock->expects($this->exactly(2)) ->method('getResource') ->willReturn($this->abstractDbMock); - $this->groupMock->expects($this->once()) + $this->groupMock->expects($this->exactly(2)) ->method('setData') - ->with($this->trimmedGroup) - ->willReturnSelf(); - $this->groupMock->expects($this->exactly(3)) + ->withConsecutive( + [$this->equalTo($this->trimmedGroup[0])], + [$this->equalTo($this->trimmedGroup[1])] + )->willReturnSelf(); + + $this->groupMock->expects($this->exactly(6)) ->method('getResource') ->willReturn($this->abstractDbMock); - $this->groupMock->expects($this->once()) + $this->groupMock->expects($this->exactly(2)) ->method('getDefaultStoreId') ->willReturn($defaultStoreId); - $this->groupMock->expects($this->once()) + $this->groupMock->expects($this->exactly(2)) ->method('setDefaultStoreId') ->with($storeId); - $this->groupMock->expects($this->once()) + $this->groupMock->expects($this->exactly(2)) ->method('setWebsite') ->with($this->websiteMock); - $this->storeMock->expects($this->once()) + $this->storeMock->expects($this->exactly(2)) ->method('getResource') ->willReturn($this->abstractDbMock); - $this->storeMock->expects($this->once()) + $this->storeMock->expects($this->exactly(2)) ->method('getStoreId') ->willReturn($storeId); @@ -312,11 +331,11 @@ public function testRunGroup() ->method('load') ->withConsecutive([$this->websiteMock, 'base', 'code'], [$this->storeMock, 'default', 'code']) ->willReturnSelf(); - $this->abstractDbMock->expects($this->exactly(2)) + $this->abstractDbMock->expects($this->exactly(4)) ->method('save') ->with($this->groupMock) ->willReturnSelf(); - $this->abstractDbMock->expects($this->once()) + $this->abstractDbMock->expects($this->exactly(2)) ->method('addCommitCallback') ->willReturnCallback(function ($function) { return $function(); From c8ac4261ef79f5259855f7460e08a8662dad7589 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 7 Nov 2018 15:31:52 -0600 Subject: [PATCH 0532/1158] MAGETWO-95770: Saved multi line attribute data displayed incorrectly on customer edit address page - Fixed multiline customer address attribute data processing for admin --- .../Magento/Customer/Model/Customer/DataProvider.php | 11 +++++++++-- .../AdminCustomerAccountInformationSection.xml | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index ce976d3f62c74..a3e121d3ce71a 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -25,6 +25,7 @@ use Magento\Framework\Session\SessionManagerInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool; +use Magento\Ui\Component\Form\Element\Multiline; use Magento\Ui\Component\Form\Field; use Magento\Ui\DataProvider\EavValidationRules; @@ -596,8 +597,14 @@ protected function prepareAddressData($addressId, array &$addresses, array $cust ) { $addresses[$addressId]['default_shipping'] = $customer['default_shipping']; } - if (isset($addresses[$addressId]['street']) && !is_array($addresses[$addressId]['street'])) { - $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); + + foreach ($this->meta['address']['children'] as $attributeName => $attributeMeta) { + if ($attributeMeta['arguments']['data']['config']['dataType'] === Multiline::NAME + && isset($addresses[$addressId][$attributeName]) + && !is_array($addresses[$addressId][$attributeName]) + ) { + $addresses[$addressId][$attributeName] = explode("\n", $addresses[$addressId][$attributeName]); + } } } diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml index a8c079824eff3..e9776a43e3df5 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml @@ -12,6 +12,7 @@ <element name="statusInactive" type="button" selector=".admin__actions-switch-label"/> <element name="accountInformationTitle" type="text" selector=".admin__page-nav-title"/> <element name="accountInformationButton" type="text" selector="//a/span[text()='Account Information']"/> + <element name="addressesButton" type="text" selector="//a/span[text()='Addresses']"/> <element name="firstName" type="input" selector="input[name='customer[firstname]']"/> <element name="lastName" type="input" selector="input[name='customer[lastname]']"/> <element name="email" type="input" selector="input[name='customer[email]']"/> From e7247de8e972674bf95bc46f6eccb8b958c64392 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 7 Nov 2018 15:35:46 -0600 Subject: [PATCH 0533/1158] MAGETWO-95770: Saved multi line attribute data displayed incorrectly on customer edit address page - Fixed static issues --- app/code/Magento/Customer/Model/Customer/DataProvider.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index a3e121d3ce71a..31f126e937c92 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -30,6 +30,8 @@ use Magento\Ui\DataProvider\EavValidationRules; /** + * Supplies the data for the customer UI component + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * * @api @@ -156,10 +158,11 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param Config $eavConfig * @param FilterPool $filterPool * @param FileProcessorFactory $fileProcessorFactory - * @param ContextInterface $context * @param array $meta * @param array $data + * @param ContextInterface $context * @param bool $allowToShowHiddenAttributes + * @throws \Magento\Framework\Exception\LocalizedException * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( From b027ce062c33745cc23fae044566520c584ba459 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Wed, 7 Nov 2018 16:25:57 -0600 Subject: [PATCH 0534/1158] ENGCOM-3409: Skip randomly failing tests in PR #2316 --- ...dminSubmitConfigurableProductOrderTest.xml | 259 +++++++++--------- .../Test/Mftf/Test/AdminTaxReportGridTest.xml | 3 + .../Mftf/Test/StorefrontTaxQuoteCartTest.xml | 3 + 3 files changed, 137 insertions(+), 128 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitConfigurableProductOrderTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitConfigurableProductOrderTest.xml index e32e6b9e6ec5d..ff1e27a2efa08 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitConfigurableProductOrderTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitConfigurableProductOrderTest.xml @@ -1,129 +1,132 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminSubmitConfigurableProductOrderTest"> - <annotations> - <title value="Create Order in Admin and update product configuration"/> - <stories value="MAGETWO-59632: Create Sales > Order from admin add configurable product and change options click OK does not update Items Ordered List"/> - <description value="Create Order in Admin and update product configuration"/> - <features value="Sales"/> - <severity value="AVERAGE"/> - <testCaseId value="MAGETWO-59633"/> - <group value="Sales"/> - </annotations> - - <before> - <!--Set default flat rate shipping method settings--> - <createData entity="FlatRateShippingMethodDefault" stepKey="setDefaultFlatRateShippingMethod"/> - - <!--Create simple customer--> - <createData entity="Simple_US_Customer_CA" stepKey="simpleCustomer"/> - - <!-- Create the category --> - <createData entity="ApiCategory" stepKey="createCategory"/> - - <!-- Create the configurable product and add it to the category --> - <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - - <!-- Create an attribute with two options to be used in the first child product --> - <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> - <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - </createData> - <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - </createData> - - <!-- Add the attribute we just created to default attribute set --> - <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - </createData> - - <!-- Get the option of the attribute we created --> - <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - </getData> - <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOption2"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - </getData> - - <!-- Create a simple product and give it the attribute with option --> - <createData entity="ApiSimpleOne" stepKey="createConfigChildProduct1"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - <requiredEntity createDataKey="getConfigAttributeOption1"/> - </createData> - <createData entity="ApiSimpleTwo" stepKey="createConfigChildProduct2"> - <requiredEntity createDataKey="createConfigProductAttribute"/> - <requiredEntity createDataKey="getConfigAttributeOption2"/> - </createData> - - <!-- Create the configurable product --> - <createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption"> - <requiredEntity createDataKey="createConfigProduct"/> - <requiredEntity createDataKey="createConfigProductAttribute"/> - <requiredEntity createDataKey="getConfigAttributeOption1"/> - <requiredEntity createDataKey="getConfigAttributeOption2"/> - </createData> - - <!-- Add simple product to the configurable product --> - <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild1"> - <requiredEntity createDataKey="createConfigProduct"/> - <requiredEntity createDataKey="createConfigChildProduct1"/> - </createData> - <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild2"> - <requiredEntity createDataKey="createConfigProduct"/> - <requiredEntity createDataKey="createConfigChildProduct2"/> - </createData> - - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> - </before> - - <!--Create new customer order--> - <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> - <argument name="customer" value="$$simpleCustomer$$"/> - </actionGroup> - - <!--Add configurable product to order--> - <actionGroup ref="addConfigurableProductToOrderFromAdmin" stepKey="addConfigurableProductToOrder"> - <argument name="product" value="$$createConfigProduct$$"/> - <argument name="attribute" value="$$createConfigProductAttribute$$"/> - <argument name="option" value="$$getConfigAttributeOption1$$"/> - </actionGroup> - - <!--Configure ordered configurable product--> - <actionGroup ref="configureOrderedConfigurableProduct" stepKey="configureOrderedConfigurableProduct"> - <argument name="attribute" value="$$createConfigProductAttribute$$"/> - <argument name="option" value="$$getConfigAttributeOption2$$"/> - <argument name="quantity" value="2"/> - </actionGroup> - - <!--Select FlatRate shipping method--> - <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> - - <!--Submit order--> - <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitOrder"/> - - <!--Verify order information--> - <actionGroup ref="verifyCreatedOrderInformation" stepKey="verifyCreatedOrderInformation"/> - - <after> - <actionGroup ref="logout" stepKey="logout"/> - - <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> - - <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> - <deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/> - <deleteData createDataKey="createConfigChildProduct2" stepKey="deleteConfigChildProduct2"/> - <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> - <deleteData createDataKey="createCategory" stepKey="deleteApiCategory"/> - </after> - </test> +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminSubmitConfigurableProductOrderTest"> + <annotations> + <title value="Create Order in Admin and update product configuration"/> + <stories value="MAGETWO-59632: Create Sales > Order from admin add configurable product and change options click OK does not update Items Ordered List"/> + <description value="Create Order in Admin and update product configuration"/> + <features value="Sales"/> + <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-59633"/> + <group value="Sales"/> + <skip> + <issueId value="MAGETWO-96196"/> + </skip> + </annotations> + + <before> + <!--Set default flat rate shipping method settings--> + <createData entity="FlatRateShippingMethodDefault" stepKey="setDefaultFlatRateShippingMethod"/> + + <!--Create simple customer--> + <createData entity="Simple_US_Customer_CA" stepKey="simpleCustomer"/> + + <!-- Create the category --> + <createData entity="ApiCategory" stepKey="createCategory"/> + + <!-- Create the configurable product and add it to the category --> + <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <!-- Create an attribute with two options to be used in the first child product --> + <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + + <!-- Add the attribute we just created to default attribute set --> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + + <!-- Get the option of the attribute we created --> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create a simple product and give it the attribute with option --> + <createData entity="ApiSimpleOne" stepKey="createConfigChildProduct1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createConfigChildProduct2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + + <!-- Create the configurable product --> + <createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + + <!-- Add simple product to the configurable product --> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild1"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigChildProduct1"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild2"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigChildProduct2"/> + </createData> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <!--Create new customer order--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> + <argument name="customer" value="$$simpleCustomer$$"/> + </actionGroup> + + <!--Add configurable product to order--> + <actionGroup ref="addConfigurableProductToOrderFromAdmin" stepKey="addConfigurableProductToOrder"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="attribute" value="$$createConfigProductAttribute$$"/> + <argument name="option" value="$$getConfigAttributeOption1$$"/> + </actionGroup> + + <!--Configure ordered configurable product--> + <actionGroup ref="configureOrderedConfigurableProduct" stepKey="configureOrderedConfigurableProduct"> + <argument name="attribute" value="$$createConfigProductAttribute$$"/> + <argument name="option" value="$$getConfigAttributeOption2$$"/> + <argument name="quantity" value="2"/> + </actionGroup> + + <!--Select FlatRate shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> + + <!--Submit order--> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitOrder"/> + + <!--Verify order information--> + <actionGroup ref="verifyCreatedOrderInformation" stepKey="verifyCreatedOrderInformation"/> + + <after> + <actionGroup ref="logout" stepKey="logout"/> + + <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> + + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> + <deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/> + <deleteData createDataKey="createConfigChildProduct2" stepKey="deleteConfigChildProduct2"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> + <deleteData createDataKey="createCategory" stepKey="deleteApiCategory"/> + </after> + </test> </tests> \ No newline at end of file diff --git a/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxReportGridTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxReportGridTest.xml index 68fe8087c4fcd..05b85a3a55cb1 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxReportGridTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxReportGridTest.xml @@ -17,6 +17,9 @@ <severity value="MAJOR"/> <testCaseId value="MAGETWO-94338"/> <group value="Tax"/> + <skip> + <issueId value="MAGETWO-96193"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml index 3b741e7bf79ec..b87ab626d3970 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml @@ -17,6 +17,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-295"/> <group value="Tax"/> + <skip> + <issueId value="MAGETWO-96194"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> From 4c495f2faa29edcaeebfe1ca1691754f3ef41b55 Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Wed, 7 Nov 2018 20:00:53 -0500 Subject: [PATCH 0535/1158] rebalance integration tests to prevent travis timeout --- dev/travis/before_script.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index 1dccc310c7a20..3bd671dbaf800 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -13,9 +13,9 @@ case $TEST_SUITE in test_set_list=$(find testsuite/* -maxdepth 1 -mindepth 1 -type d | sort) test_set_count=$(printf "$test_set_list" | wc -l) - test_set_size[1]=$(printf "%.0f" $(echo "$test_set_count*0.17" | bc)) #17% - test_set_size[2]=$(printf "%.0f" $(echo "$test_set_count*0.27" | bc)) #27% - test_set_size[3]=$((test_set_count-test_set_size[1]-test_set_size[2])) #56% + test_set_size[1]=$(printf "%.0f" $(echo "$test_set_count*0.13" | bc)) #13% + test_set_size[2]=$(printf "%.0f" $(echo "$test_set_count*0.30" | bc)) #30% + test_set_size[3]=$((test_set_count-test_set_size[1]-test_set_size[2])) #55% echo "Total = ${test_set_count}; Batch #1 = ${test_set_size[1]}; Batch #2 = ${test_set_size[2]}; Batch #3 = ${test_set_size[3]};"; echo "==> preparing integration testsuite on index $INTEGRATION_INDEX with set size of ${test_set_size[$INTEGRATION_INDEX]}" From bd34b53918b3c159b5ceb87ac59f66c84f1b76ee Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Thu, 8 Nov 2018 10:48:18 +0300 Subject: [PATCH 0536/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../view/adminhtml/web/js/grouped-product-grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index c06f615ae48e6..91454e8b3de78 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -114,7 +114,7 @@ define([ /** * - * @param {Array} recordData to reprocess + * @param {Array} - recordData to reprocess */ reloadGridData: function (recordData) { this.recordData(recordData.sort(function (a, b) { From 9ca93f97c170b26e0f90be10325cdcc5d296524f Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 8 Nov 2018 10:37:04 +0200 Subject: [PATCH 0537/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add json response to delete, mass delete address actions; --- .../Controller/Adminhtml/Address/Delete.php | 52 ++++++++++---- .../Adminhtml/Address/MassDelete.php | 70 ++++++++++++++----- .../Controller/Adminhtml/Address/Save.php | 6 +- .../Customer/Model/Address/DataProvider.php | 26 +++---- 4 files changed, 110 insertions(+), 44 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 7630dba780357..3caba47961af0 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,14 +8,16 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\App\Action\HttpDeleteActionInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; +use Psr\Log\LoggerInterface; /** * Button for deletion of customer address in admin * */ -class Delete extends Action implements HttpPostActionInterface +class Delete extends Action implements HttpDeleteActionInterface { /** * Authorization level of a basic admin session @@ -29,39 +31,65 @@ class Delete extends Action implements HttpPostActionInterface */ private $addressRepository; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @param Action\Context $context * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param JsonFactory $resultJsonFactory + * @param LoggerInterface $logger */ public function __construct( Action\Context $context, - AddressRepositoryInterface $addressRepository + AddressRepositoryInterface $addressRepository, + JsonFactory $resultJsonFactory, + LoggerInterface $logger ) { parent::__construct($context); $this->addressRepository = $addressRepository; + $this->resultJsonFactory = $resultJsonFactory; + $this->logger = $logger; } /** * Delete customer address action * - * @return \Magento\Framework\Controller\Result\Redirect + * @return Json * @throws \Magento\Framework\Exception\LocalizedException */ - public function execute(): Redirect + public function execute(): Json { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('id', false); + $error = false; + $message = ''; if ($addressId && $this->addressRepository->getById($addressId)->getCustomerId() === $customerId) { try { $this->addressRepository->deleteById($addressId); - $this->messageManager->addSuccessMessage(__('You deleted the address.')); - } catch (\Exception $other) { - $this->messageManager->addExceptionMessage($other, __('We can\'t delete the address right now.')); + $message = __('You deleted the address.'); + } catch (\Exception $e) { + $error = true; + $message = __('We can\'t delete the address right now.'); + $this->logger->critical($e); } } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); - return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + ] + ); + + return $resultJson; } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index b8df3fdf81599..09523f9e6a956 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -8,12 +8,15 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Controller\Result\Json; use Magento\Backend\App\Action\Context; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Ui\Component\MassAction\Filter; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; use Magento\Customer\Api\AddressRepositoryInterface; -use Magento\Backend\Model\View\Result\Redirect; +use Psr\Log\LoggerInterface; /** * Class to delete selected customer addresses through massaction @@ -38,52 +41,85 @@ class MassDelete extends Action implements HttpPostActionInterface protected $collectionFactory; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var JsonFactory + */ + private $resultJsonFactory; + /** * @param Context $context * @param Filter $filter * @param CollectionFactory $collectionFactory * @param AddressRepositoryInterface $addressRepository + * @param LoggerInterface $logger + * @param JsonFactory $resultJsonFactory */ public function __construct( Context $context, Filter $filter, CollectionFactory $collectionFactory, - AddressRepositoryInterface $addressRepository + AddressRepositoryInterface $addressRepository, + LoggerInterface $logger, + JsonFactory $resultJsonFactory ) { $this->filter = $filter; $this->collectionFactory = $collectionFactory; $this->addressRepository = $addressRepository; + $this->logger = $logger; + $this->resultJsonFactory = $resultJsonFactory; parent::__construct($context); } /** * Delete specified customer addresses using grid massaction * - * @return Redirect - * @throws \Magento\Framework\Exception\LocalizedException|\Exception + * @return Json + * @throws LocalizedException */ - public function execute(): Redirect + public function execute(): Json { /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ $collection = $this->filter->getCollection($this->collectionFactory->create()); $collectionSize = $collection->getSize(); + $error = false; - // Get id of the first item from addresses collection for the ResultRedirect and build a correct redirect URL - $customerId = $collection->getFirstItem()->getParentId(); - - /** @var \Magento\Customer\Model\Address $address */ - foreach ($collection as $address) { - $this->addressRepository->deleteById($address->getId()); + try { + /** @var \Magento\Customer\Model\Address $address */ + foreach ($collection as $address) { + $this->addressRepository->deleteById($address->getId()); + } + $message = __('A total of %1 record(s) have been deleted.', $collectionSize); + } catch (NoSuchEntityException $e) { + $message = __('There is no such address entity to delete.'); + $error = true; + $this->logger->critical($e); + } catch (LocalizedException $e) { + $message = __($e->getMessage()); + $error = true; + $this->logger->critical($e); + } catch (\Exception $e) { + $message = __('We can\'t mass delete the addresses right now.'); + $error = true; + $this->logger->critical($e); } - $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been deleted.', $collectionSize)); - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + ] + ); - return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + return $resultJson; } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 3bd49d038588c..855b8aedb1f73 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -8,8 +8,8 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; -use Magento\Framework\Controller\ResultInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Psr\Log\LoggerInterface; @@ -94,9 +94,9 @@ public function __construct( /** * Save customer address action * - * @return ResultInterface + * @return Json */ - public function execute(): ResultInterface + public function execute(): Json { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('entity_id', false); diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index a7c0da08324d3..c41214b91b8c2 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -126,18 +126,20 @@ public function getData(): array if (null !== $this->loadedData) { return $this->loadedData; } - /** @var Address $address */ - $address = $this->collection->getFirstItem(); - $addressId = $address->getEntityId(); - $address->load($addressId); - $this->loadedData[$addressId] = $address->getData(); - $customerId = $this->loadedData[$addressId]['parent_id']; - /** @var \Magento\Customer\Model\Customer $customer */ - $customer = $this->customerRepository->getById($customerId); - $defaultBilling = $customer->getDefaultBilling(); - $defaultShipping = $customer->getDefaultShipping(); - $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); - $this->fileUploaderDataResolver->overrideFileUploaderData($address, $this->loadedData[$addressId]); + $items = $this->collection->getItems(); + /** @var Address $item */ + foreach ($items as $item) { + $addressId = $item->getEntityId(); + $item->load($addressId); + $this->loadedData[$addressId] = $item->getData(); + $customerId = $this->loadedData[$addressId]['parent_id']; + /** @var \Magento\Customer\Model\Customer $customer */ + $customer = $this->customerRepository->getById($customerId); + $defaultBilling = $customer->getDefaultBilling(); + $defaultShipping = $customer->getDefaultShipping(); + $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); + $this->fileUploaderDataResolver->overrideFileUploaderData($item, $this->loadedData[$addressId]); + } if (null === $this->loadedData) { $this->loadedData[''] = $this->getDefaultData(); From 14bc369dfce948a564a46178a7c2a413b3b71b1a Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 8 Nov 2018 11:40:51 +0200 Subject: [PATCH 0538/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add json response to set default shipping, set default billing actions; --- .../Address/AbstractDefaultAddress.php | 53 +++++++++++++------ .../Controller/Adminhtml/Address/Delete.php | 10 ++-- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index 51e02e9ee096e..9ec38f4929a87 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -8,15 +8,17 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; use Magento\Framework\Phrase; use Psr\Log\LoggerInterface; /** * Abstract class for customer default addresses changing */ -abstract class AbstractDefaultAddress extends Action implements HttpPostActionInterface +abstract class AbstractDefaultAddress extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -26,7 +28,7 @@ abstract class AbstractDefaultAddress extends Action implements HttpPostActionIn public const ADMIN_RESOURCE = 'Magento_Customer::manage'; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; @@ -35,46 +37,63 @@ abstract class AbstractDefaultAddress extends Action implements HttpPostActionIn */ private $logger; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + /** * @param Action\Context $context - * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param AddressRepositoryInterface $addressRepository * @param LoggerInterface $logger + * @param JsonFactory $resultJsonFactory */ public function __construct( Action\Context $context, - \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, - LoggerInterface $logger + AddressRepositoryInterface $addressRepository, + LoggerInterface $logger, + JsonFactory $resultJsonFactory ) { parent::__construct($context); $this->addressRepository = $addressRepository; $this->logger = $logger; + $this->resultJsonFactory = $resultJsonFactory; } /** * Execute action to set customer default billing or shipping address * - * @return \Magento\Framework\Controller\Result\Redirect + * @return Json */ - public function execute(): Redirect + public function execute(): Json { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('id', false); + $error = false; + $message = ''; + if ($addressId) { try { $address = $this->addressRepository->getById($addressId)->setCustomerId($customerId); $this->setAddressAsDefault($address); $this->addressRepository->save($address); - - $this->messageManager->addSuccessMessage($this->getSuccessMessage()); - } catch (\Exception $other) { - $this->logger->critical($other); - $this->messageManager->addExceptionMessage($other, $this->getExceptionMessage()); + $message = $this->getSuccessMessage(); + } catch (\Exception $e) { + $error = true; + $message = $this->getExceptionMessage(); + $this->logger->critical($e); } } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); - return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + ] + ); + + return $resultJson; } /** diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 3caba47961af0..65da3bca49e9b 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,16 +8,16 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpDeleteActionInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; use Psr\Log\LoggerInterface; /** - * Button for deletion of customer address in admin * + * Button for deletion of customer address in admin */ -class Delete extends Action implements HttpDeleteActionInterface +class Delete extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -27,7 +27,7 @@ class Delete extends Action implements HttpDeleteActionInterface public const ADMIN_RESOURCE = 'Magento_Customer::manage'; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; @@ -43,7 +43,7 @@ class Delete extends Action implements HttpDeleteActionInterface /** * @param Action\Context $context - * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param AddressRepositoryInterface $addressRepository * @param JsonFactory $resultJsonFactory * @param LoggerInterface $logger */ From e0360fea947d2392b66d4a11ccbe195fe8f3758e Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Thu, 8 Nov 2018 12:53:11 +0200 Subject: [PATCH 0539/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - create MFTF test to cover fix --- .../ActionGroup/AdminOrderBraintreeFill.xml | 43 +++++++ .../Test/Mftf/Data/BraintreeData.xml | 1 + .../Test/Mftf/Section/AdminMenuSection.xml | 2 +- ...thOnlinePaymentIncludingTaxAndDiscount.xml | 110 ++++++++++++++++++ .../ActionGroup/AdminInvoiceActionGroup.xml | 13 +++ .../ActionGroup/AdminOrderActionGroup.xml | 1 + .../AdminInvoiceMainActionsSection.xml | 2 + .../Section/AdminOrderInvoicesTabSection.xml | 1 + .../AdminCreateCartPriceRuleActionGroup.xml | 31 +++++ .../AdminCartPriceRulesFormSection.xml | 1 + .../Section/CartPriceRulesSubmenuSection.xml | 14 +++ .../Mftf/ActionGroup/AdminTaxActionGroup.xml | 27 +++++ .../Mftf/Section/AdminConfigureTaxSection.xml | 4 + 13 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml create mode 100644 app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml create mode 100644 app/code/Magento/SalesRule/Test/Mftf/Section/CartPriceRulesSubmenuSection.xml diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml new file mode 100644 index 0000000000000..6ef70b1f38660 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + + <actionGroup name="AdminOrderBraintreeFill"> + + <!--Select Braintree Payment method on Admin Order Create Page--> + <click stepKey="chooseBraintree" selector="{{NewOrderSection.creditCardBraintree}}"/> + <waitForPageLoad stepKey="waitForBraintreeConfigs" time="5"/> + <click stepKey="openCardTypes" selector="{{NewOrderSection.openCardTypes}}"/> + <waitForPageLoad stepKey="waitForCardTypes" time="3"/> + <click stepKey="chooseCardType" selector="{{NewOrderSection.masterCard}}"/> + <waitForPageLoad stepKey="waitForCardSelected" time="3"/> + + <!--Choose Master Card from drop-down list--> + <switchToIFrame stepKey="switchToCardNumber" selector="{{NewOrderSection.cardFrame}}"/> + <fillField stepKey="fillCardNumber" selector="{{NewOrderSection.creditCardNumber}}" userInput="{{PaymentAndShippingInfo.cardNumber}}"/> + <waitForPageLoad stepKey="waitForFillCardNumber" time="1"/> + <switchToIFrame stepKey="switchBackFromCard"/> + + <!--Fill expire date--> + <switchToIFrame stepKey="switchToExpirationMonth" selector="{{NewOrderSection.monthFrame}}"/> + <fillField stepKey="fillMonth" selector="{{NewOrderSection.expirationMonth}}" userInput="{{PaymentAndShippingInfo.month}}"/> + <waitForPageLoad stepKey="waitForFillMonth" time="1"/> + <switchToIFrame stepKey="switchBackFromMonth"/> + <switchToIFrame stepKey="switchToExpirationYear" selector="{{NewOrderSection.yearFrame}}"/> + <fillField stepKey="fillYear" selector="{{NewOrderSection.expirationYear}}" userInput="{{PaymentAndShippingInfo.year}}"/> + <waitForPageLoad stepKey="waitForFillYear" time="1"/> + <switchToIFrame stepKey="switchBackFromYear"/> + + <!--Fill CVW code--> + <switchToIFrame stepKey="switchToCVV" selector="{{NewOrderSection.cvvFrame}}"/> + <fillField stepKey="fillCVV" selector="{{NewOrderSection.cvv}}" userInput="{{PaymentAndShippingInfo.cvv}}"/> + <wait stepKey="waitForFillCVV" time="1"/> + <switchToIFrame stepKey="switchBackFromCVV"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml index 8f2588a6effa5..ff98b6c91b5a9 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml @@ -42,6 +42,7 @@ <requiredEntity type="merchant_id">MerchantId</requiredEntity> <requiredEntity type="public_key">PublicKey</requiredEntity> <requiredEntity type="private_key">PrivateKey</requiredEntity> + <requiredEntity type="active">Status</requiredEntity> </entity> <entity name="BraintreeTitle" type="title"> <data key="value">Credit Card (Braintree)</data> diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml index 660c7393b4061..eb7a9ce2c376e 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml @@ -13,7 +13,7 @@ <element name="sales" type="button" selector="//li[@id='menu-magento-sales-sales']"/> <element name="catalog" type="button" selector="//li[@id='menu-magento-catalog-catalog']"/> <element name="customers" type="button" selector="//li[@id='menu-magento-customer-customer']"/> - <element name="marketing" type="button" selector="//li[@id='//li[@id='menu-magento-backend-marketing']']"/> + <element name="marketing" type="button" selector="//li[@id='menu-magento-backend-marketing']"/> <element name="content" type="button" selector="//li[@id='menu-magento-backend-content']"/> <element name="reports" type="button" selector="//li[@id='menu-magento-reports-report']"/> <element name="stores" type="button" selector="//li[@id='menu-magento-backend-stores']"/> diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml new file mode 100644 index 0000000000000..470c425f3dae1 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CreateAdminOrderPayedWithOnlinePaymentIncludingTaxAndDiscount"> + <annotations> + <features value="Sales"/> + <stories value="Get access to a New Credit Memo Page from Invocie for Order payed with online payment via Admin"/> + <title value="Admin should be able to open a New Credit Memo Page from Invoice Page for Order with tax and discount and payed using online payment method"/> + <description value="Admin should be able to open a New Credit Memo Page from Invoice Page for Order with tax and discount and payed using online payment method"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-94472"/> + <group value="sales"/> + </annotations> + + <before> + <!--Create Default Category--> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + + <!--Create Simple product with Special Price--> + <createData entity="_defaultProduct" stepKey="simpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <!--Create Tax Rule is based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> + <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> + + <!--Configure Braintree Payment method--> + <createData entity="BraintreeConfig" stepKey="BraintreeConfigurationData"/> + <createData entity="CustomBraintreeConfigurationData" stepKey="enableBraintree"/> + + <!--Create Retailer Customer with US_CA address--> + <createData entity="Simple_US_Customer_CA" stepKey="simpleCustomer"> + <field key="group_id">3</field> + </createData> + + <!--Login as Admin User--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <after> + <!--Delete Cart Price Rule--> + <actionGroup ref="AdminDeleteCartPriceRuleForRetailerActionGroup" stepKey="deleteSalesRule"/> + + <!--Delete Simple Sub Category--> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!--Delete Simple Product--> + <deleteData createDataKey="simpleProduct" stepKey="deleteSimpleProduct"/> + + <!-- Delete Tax Rule --> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + + <!-- Rollback Braintree to Default --> + <createData entity="DefaultBraintreeConfig" stepKey="DefaultBraintreeConfig"/> + + <!--Delete Customer--> + <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> + + <!--Log Out--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create a cart price rule for Fixed amount discount for whole cart --> + <actionGroup ref="AdminCreateCartPriceRuleForRetailerActionGroup" stepKey="createCartPriceRule"/> + + <!--Set Taxable Goods for Shipping Tax Class--> + <actionGroup ref="changeShippingTaxClass" stepKey="changeShippingTaxClass"/> + + <!--Adding Special price to product--> + <amOnPage url="{{AdminProductEditPage.url($$simpleProduct.id$$)}}" stepKey="openAdminProductEditPage"/> + <actionGroup ref="AddSpecialPriceToProductActionGroup" stepKey="addSpecialPrice"/> + <actionGroup ref="saveProductForm" stepKey="saveProductForm"/> + + <!--Create New Order--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> + <argument name="customer" value="$$simpleCustomer$$"/> + </actionGroup> + + <!--Add a product to order--> + <actionGroup ref="addSimpleProductToOrder" stepKey="addProductToOrder"> + <argument name="product" value="$$simpleProduct$$"/> + </actionGroup> + + <!--Select FlatRate shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> + + <!--Select Braintree online Payment method --> + <actionGroup ref="AdminOrderBraintreeFill" stepKey="selectCreditCardPayment"/> + + <!--Submit Order--> + <click stepKey="submitOrder" selector="{{NewOrderSection.submitOrder}}"/> + <waitForPageLoad stepKey="waitForSaveConfig" time="10"/> + <waitForElementVisible selector="{{NewOrderSection.successMessage}}" stepKey="waitForSuccessMessage" time="5"/> + + <!-- Create New invoice--> + <actionGroup ref="adminFastCreateInvoice" stepKey="createInvoice"/> + + <!--Get access to Credit Memo page from Invocie page--> + <click selector="{{AdminInvoiceMainActionsSection.openNewCreditMemoFromInvoice}}" stepKey="clickCreateNewCreditMemo"/> + <waitForPageLoad stepKey="waitForLoadNewCreditMemoPage" time="5"/> + <waitForElementVisible selector="{{AdminCreditMemoOrderInformationSection.orderId}}" stepKey="waitForOrderIdOnCreditMemoPage"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml index 15aff7c751a11..6cda4e143c926 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml @@ -38,4 +38,17 @@ </arguments> <see selector="{{AdminInvoiceItemsSection.skuColumn}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> </actionGroup> + + <!--Admin Fast Create Invoice--> + <actionGroup name="adminFastCreateInvoice"> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceButton"/> + <waitForPageLoad stepKey="waitForNewInvoicePageLoad" time="3"/> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <waitForPageLoad stepKey="waitForSuccessMessageLoad" time="5"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeSuccessMessage"/> + <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoices"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask5" /> + <click selector="{{AdminOrderInvoicesTabSection.viewInvoice}}" stepKey="openInvoicePage"/> + <waitForPageLoad stepKey="waitForInvoicePageLoad" time="5"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index c82623632d782..4801c3c6f85a6 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -92,6 +92,7 @@ <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="1" stepKey="fillProductQty"/> <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + <wait time="5" stepKey="waitForOptionsToLoad"/> </actionGroup> <!--Add configurable product to order --> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml index 2a241708517bf..bc7fc8145af33 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml @@ -10,5 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminInvoiceMainActionsSection"> <element name="submitInvoice" type="button" selector=".action-default.scalable.save.submit-button.primary"/> + <element name="openNewCreditMemoFromInvoice" type="button" selector=".action-default.scalable.credit-memo"/> + <element name="submitNewRefundFromInvoice" type="button" selector=".action-default.scalable.save.submit-button refund primary"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml index b33276bed527e..4ebce4de6b383 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml @@ -12,5 +12,6 @@ <element name="spinner" type="text" selector="[data-role='spinner'][data-component*='sales_order_view_invoice']"/> <element name="gridRow" type="text" selector="#sales_order_view_tabs_order_invoices_content .data-grid tbody > tr:nth-of-type({{row}})" parameterized="true"/> <element name="viewGridRow" type="button" selector="#sales_order_view_tabs_order_invoices_content .data-grid tbody > tr:nth-of-type({{row}}) a[href*='order_invoice/view']" parameterized="true"/> + <element name="viewInvoice" type="button" selector="//div[@class='admin__data-grid-wrap']//a[@class='action-menu-item']"/> </section> </sections> \ No newline at end of file diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml index 87947fba8095a..6a837577ece3d 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml @@ -23,4 +23,35 @@ <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> </actionGroup> + + <!--Create Cart price Rule for Retailer customer--> + <actionGroup name="AdminCreateCartPriceRuleForRetailerActionGroup"> + <click selector="{{AdminMenuSection.marketing}}" stepKey="clickOnMarketing" /> + <waitForPageLoad stepKey="waitForMarketing" time="3"/> + <click selector="{{CartPriceRulesSubmenuSection.cartPriceRules}}" stepKey="clickOnCartPriceRules"/> + <waitForPageLoad stepKey="waitForCartPriceRules" time="5"/> + <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRule"/> + <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{SimpleSalesRule.name}}" stepKey="fillRuleName"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="selectWebsites"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="Retailer" stepKey="selectCustomerGroup"/> + <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Percent of product price discount" stepKey="selectActionType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="10" stepKey="fillDiscountAmount"/> + <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> + <waitForPageLoad stepKey="waitForCartRuleLoad" time="5"/> + <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> + </actionGroup> + + <!--Delete Cart price Rule for Retailer customer--> + <actionGroup name="AdminDeleteCartPriceRuleForRetailerActionGroup"> + <click selector="{{AdminMenuSection.marketing}}" stepKey="clickOnMarketing" /> + <waitForPageLoad stepKey="waitForMarketing" time="3"/> + <click selector="{{CartPriceRulesSubmenuSection.cartPriceRules}}" stepKey="clickOnCartPriceRules"/> + <waitForPageLoad stepKey="waitForCartPriceRules" time="5"/> + <fillField selector="{{AdminCartPriceRulesSection.filterByNameInput}}" userInput="{{SimpleSalesRule.name}}" stepKey="filterByName"/> + <click selector="{{AdminCartPriceRulesSection.searchButton}}" stepKey="doFilter"/> + <click selector="{{AdminCartPriceRulesSection.rowByIndex('1')}}" stepKey="goToEditRulePage"/> + <click selector="{{AdminCartPriceRulesFormSection.delete}}" stepKey="clickDeleteButton"/> + <click selector="{{AdminCartPriceRulesFormSection.modalAcceptButton}}" stepKey="confirmDelete"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml b/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml index d8253505c42e4..480c266101dba 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml @@ -26,6 +26,7 @@ <element name="priority" type="input" selector="//*[@name='sort_order']"/> <!-- Actions sub-form --> + <element name="actionsTab" type="text" selector="//div[@data-index='actions']//span[contains(.,'Actions')][1]"/> <element name="actionsHeader" type="button" selector="div[data-index='actions']" timeout="30"/> <element name="apply" type="select" selector="select[name='simple_action']"/> <element name="conditions" type="button" selector=".rule-param.rule-param-new-child > a"/> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Section/CartPriceRulesSubmenuSection.xml b/app/code/Magento/SalesRule/Test/Mftf/Section/CartPriceRulesSubmenuSection.xml new file mode 100644 index 0000000000000..f3d5e9627efcf --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Section/CartPriceRulesSubmenuSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CartPriceRulesSubmenuSection"> + <element name="cartPriceRules" type="button" selector="//li[@data-ui-id='menu-magento-catalogrule-promo']//li[@data-ui-id='menu-magento-salesrule-promo-quote']"/> + </section> +</sections> \ No newline at end of file diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml index 1a95bf0282b40..15dcaf66f1220 100644 --- a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml @@ -115,4 +115,31 @@ <!-- Save the tax rate --> <click stepKey="saveTaxRate" selector="{{AdminTaxRulesSection.save}}"/> </actionGroup> + + <!--Set Tax Class for Shipping--> + <actionGroup name="changeShippingTaxClass"> + <!--Select Configuration menu from Store--> + <click selector="{{AdminMenuSection.stores}}" stepKey="clickOnSTORES" /> + <waitForPageLoad stepKey="waitForConfiguration" time="5"/> + <click selector="{{StoresSubmenuSection.configuration}}" stepKey="clickOnConfigurations"/> + <waitForPageLoad stepKey="waitForSales" time="5"/> + <!--Double click the same to fix flaky issue with redirection to Dashboard--> + <click selector="{{AdminMenuSection.stores}}" stepKey="clickOnSTORES1" /> + <waitForPageLoad stepKey="waitForConfiguration1" time="5"/> + <click selector="{{StoresSubmenuSection.configuration}}" stepKey="clickOnConfigurations1"/> + <waitForPageLoad stepKey="waitForSales1" time="5"/> + <!--Change default tax class for Shipping on Taxable Goods--> + <click selector="{{ConfigurationListSection.sales}}" stepKey="clickOnSales" /> + <waitForPageLoad stepKey="waitForPaymentMethods" time="5"/> + <click selector="{{AdminConfigureTaxSection.salesTax}}" stepKey="clickOnTax"/> + <waitForPageLoad stepKey="waitForTax" time="5"/> + <seeInCurrentUrl url="{{AdminTaxConfigurationPage.url}}" stepKey="adminTaxConfiguration"/> + <seeElement selector="{{AdminConfigureTaxSection.taxClasses}}" stepKey="taxClassSectionC"/> + <selectOption selector="{{AdminConfigureTaxSection.taxClassShipping}}" userInput="Taxable Goods" stepKey="setTaxClassForShipping"/> + <!-- Save the settings --> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click stepKey="saveTaxOptions" selector="{{AdminCategoryMainActionsSection.SaveButton}}"/> + <waitForPageLoad stepKey="waitForTaxSaved"/> + <see stepKey="seeSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the configuration."/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index 8e52800516dae..e0a3092c13321 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -10,7 +10,11 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminConfigureTaxSection"> <!-- on page /admin/admin/system_config/edit/section/tax/ --> + <element name="salesTax" type="button" selector="//a[contains(@class, 'admin__page-nav-link item-nav')]/span[text()='Tax']"/> <element name="taxClasses" type="block" selector="#tax_classes-head" timeout="30"/> + <element name="taxClassShipping" type="select" selector="#tax_classes_shipping_tax_class"/> + <element name="taxClassProduct" type="select" selector="#tax_classes_default_product_tax_class"/> + <element name="taxClassCustomer" type="select" selector="#tax_classes_default_customer_tax_class"/> <element name="taxCalculationSettings" type="block" selector="#tax_calculation-head" timeout="30"/> <element name="taxCalculationSettingsOpened" type="block" selector="#tax_calculation-head.open" timeout="30"/> From c7a140ea0d878c43699d535b3c307ed2ffc5f7a0 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Thu, 8 Nov 2018 16:02:50 +0300 Subject: [PATCH 0540/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../view/adminhtml/web/js/grouped-product-grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 91454e8b3de78..58c3b79022a62 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -114,7 +114,7 @@ define([ /** * - * @param {Array} - recordData to reprocess + * @param {Array} recordData - to reprocess */ reloadGridData: function (recordData) { this.recordData(recordData.sort(function (a, b) { From 50fb1cc2f50ac0b4e0c892ce474bc6c3b770cc7a Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Thu, 8 Nov 2018 15:25:05 +0200 Subject: [PATCH 0541/1158] MAGETWO-96063: [TSG] Pull Request MFTF 8 stabilization --- .../Test/Mftf/Page/AdminConfigPage.xml | 12 ++++ ...> AdminConfigAdvancedReportingSection.xml} | 7 +- .../AdminConfigurationBlankIndustryTest.xml | 15 ++-- ...onfigurationEnableDisableAnalyticsTest.xml | 35 +++++----- .../Test/AdminConfigurationIndustryTest.xml | 13 ++-- .../Test/AdminConfigurationPermissionTest.xml | 69 ++++++++++--------- .../AdminConfigurationTimeToSendDataTest.xml | 18 +++-- .../BraintreeCreditCardOnCheckoutTest.xml | 2 +- ...CategoryProductsUsingScopeSelectorTest.xml | 8 +-- ...efrontPurchaseProductWithCustomOptions.xml | 15 ++-- ...ctWithCustomOptionsWithLongValuesTitle.xml | 9 ++- .../ActionGroup/AdminCheckoutActionGroup.xml | 18 +++++ .../Mftf/ActionGroup/CheckoutActionGroup.xml | 14 +++- .../StorefrontProductCartActionGroup.xml | 4 +- .../Section/AdminCheckoutPaymentSection.xml | 14 ++++ .../Mftf/Section/CheckoutPaymentSection.xml | 2 +- ...StorefrontCheckoutPaymentMethodSection.xml | 15 ++++ .../Mftf/Test/StorefrontGuestCheckoutTest.xml | 1 + .../Test/Mftf/Section/AdminConfigSection.xml | 5 +- .../Test/Mftf/Test/AdminCreateInvoiceTest.xml | 1 + .../Mftf/Test/StorefrontTaxQuoteCartTest.xml | 4 ++ ...AssertBundleProductOnConfigureCartPage.php | 5 ++ .../app/Magento/Checkout/Test/Block/Cart.php | 17 +++++ .../Checkout/Test/Block/Cart/Shipping.php | 54 +++++++++++++++ .../Checkout/Test/Block/Cart/Totals.php | 11 +++ .../Constraint/AssertCartItemsOptions.php | 5 ++ .../AssertGrandTotalInShoppingCart.php | 4 ++ .../Constraint/AssertPriceInShoppingCart.php | 5 ++ .../AssertProductQtyInShoppingCart.php | 5 ++ .../AssertSubtotalInShoppingCart.php | 4 ++ .../Constraint/Utils/CartPageLoadTrait.php | 30 ++++++++ ...eProductFromMiniShoppingCartEntityTest.php | 1 + .../ProductsInCartReportEntityTest.php | 2 + ...oveShoppingCartProductsOnOrderPageTest.php | 1 + 34 files changed, 327 insertions(+), 98 deletions(-) create mode 100644 app/code/Magento/Analytics/Test/Mftf/Page/AdminConfigPage.xml rename app/code/Magento/Analytics/Test/Mftf/Section/{AdminConfigSection.xml => AdminConfigAdvancedReportingSection.xml} (86%) create mode 100644 app/code/Magento/Checkout/Test/Mftf/ActionGroup/AdminCheckoutActionGroup.xml create mode 100644 app/code/Magento/Checkout/Test/Mftf/Section/AdminCheckoutPaymentSection.xml create mode 100644 app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml create mode 100644 dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/Utils/CartPageLoadTrait.php diff --git a/app/code/Magento/Analytics/Test/Mftf/Page/AdminConfigPage.xml b/app/code/Magento/Analytics/Test/Mftf/Page/AdminConfigPage.xml new file mode 100644 index 0000000000000..c4ced12e67e07 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Mftf/Page/AdminConfigPage.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminConfigGeneralAnalyticsPage" url="admin/system_config/edit/section/analytics/" area="admin" module="Magento_Config"> + <section name="AdminConfigAdvancedReportingSection"/> + </page> +</pages> diff --git a/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml b/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigAdvancedReportingSection.xml similarity index 86% rename from app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml rename to app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigAdvancedReportingSection.xml index f8554a4ea115b..2e5f2b762a7b1 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigAdvancedReportingSection.xml @@ -6,8 +6,8 @@ */ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="AdminConfigSection"> - <element name="advancedReportingMenuItem" type="text" selector="//*[@id='system_config_tabs']/div[1]//span[text()='Advanced Reporting']"/> + <section name="AdminConfigAdvancedReportingSection"> + <element name="advancedReportingMenuItem" type="text" selector="//*[@class='admin__page-nav-link item-nav']//span[text()='Advanced Reporting']"/> <element name="advancedReportingService" type="select" selector="#analytics_general_enabled"/> <element name="advancedReportingServiceLabel" type="text" selector="#row_analytics_general_enabled>td.label>label>span"/> <element name="advancedReportingServiceStatus" type="text" selector="#row_analytics_general_enabled>td.value>p>span"/> @@ -17,6 +17,5 @@ <element name="advancedReportingMinute" type="select" selector="#row_analytics_general_collection_time>td:nth-child(2)>select:nth-child(3)"/> <element name="advancedReportingSeconds" type="select" selector="#row_analytics_general_collection_time>td:nth-child(2)>select:nth-child(4)"/> <element name="advancedReportingBlankIndustryError" type="text" selector=".message-error>div"/> - <element name="advancedReportingSuccessMessage" type="text" selector=".message-success>div"/> </section> -</sections> \ No newline at end of file +</sections> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml index ff89ca9b663ee..914cb59b64e4e 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml @@ -18,15 +18,14 @@ <group value="analytics"/> </annotations> <after> - <amOnPage stepKey="amOnLogoutPage" url="admin/admin/auth/logout/"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> </after> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> - <amOnPage stepKey="amOnAdminConfig" url="{{AdminConfigPage.url}}"/> - <waitForPageLoad stepKey="waitForAdminConfig"/> - <click stepKey="clickAdvancedReportingConfigMenu" selector="{{AdminConfigSection.advancedReportingMenuItem}}"/> - <see stepKey="seeAdvancedReportingIndustryLabel" selector="{{AdminConfigSection.advancedReportingIndustryLabel}}" userInput="Industry"/> - <selectOption stepKey="selectAdvancedReportingIndustry" selector="{{AdminConfigSection.advancedReportingIndustry}}" userInput="--Please Select--"/> - <click stepKey="clickSaveConfigButton" selector="{{AdminConfigSection.saveButton}}"/> - <see stepKey="seeBlankIndustryErrorMessage" selector="{{AdminConfigSection.advancedReportingBlankIndustryError}}" userInput="Please select an industry."/> + <amOnPage url="{{AdminConfigGeneralAnalyticsPage.url}}" stepKey="amOnAdminConfig"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Enable" stepKey="selectAdvancedReportingServiceEnabled"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustryLabel}}" userInput="Industry" stepKey="seeAdvancedReportingIndustryLabel"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustry}}" userInput="--Please Select--" stepKey="selectAdvancedReportingIndustry"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveConfigButton"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingBlankIndustryError}}" userInput="Please select an industry." stepKey="seeBlankIndustryErrorMessage"/> </test> </tests> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml index 1706383fc7866..1c1a3b27b06af 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml @@ -18,27 +18,24 @@ <group value="analytics"/> </annotations> <after> - <amOnPage stepKey="amOnLogoutPage" url="admin/admin/auth/logout/"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> </after> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> - <!--Goto admin stores configure page --> - <amOnPage stepKey="amOnAdminConfig" url="{{AdminConfigPage.url}}"/> - <!--Enable Advanced Reporting--> - <click stepKey="clickAdvancedReportingConfigMenu" selector="{{AdminConfigSection.advancedReportingMenuItem}}"/> - <see stepKey="seeAdvancedReportingServiceLabelEnabled" selector="{{AdminConfigSection.advancedReportingServiceLabel}}" userInput="Advanced Reporting Service"/> - <selectOption stepKey="selectAdvancedReportingServiceEnabled" selector="{{AdminConfigSection.advancedReportingService}}" userInput="Enable"/> - <see stepKey="seeAdvancedReportingIndustryLabel" selector="{{AdminConfigSection.advancedReportingIndustryLabel}}" userInput="Industry"/> - <selectOption stepKey="selectAdvancedReportingIndustry" selector="{{AdminConfigSection.advancedReportingIndustry}}" userInput="Apps and Games"/> - <click stepKey="clickSaveConfigButtonEnabled" selector="{{AdminConfigSection.saveButton}}"/> - <see stepKey="seeSaveConfigurationMessageEnabled" selector="{{AdminConfigSection.advancedReportingSuccessMessage}}" userInput="You saved the configuration."/> - <see stepKey="seeAdvancedReportingServiceEnabled" selector="{{AdminConfigSection.advancedReportingService}}" userInput="Enable"/> - <see stepKey="seeAdvancedReportingServiceStatusEnabled" selector="{{AdminConfigSection.advancedReportingServiceStatus}}" userInput="Subscription status: Pending"/> + <amOnPage url="{{AdminConfigGeneralAnalyticsPage.url}}" stepKey="amOnAdminConfig"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingServiceLabel}}" userInput="Advanced Reporting Service" stepKey="seeAdvancedReportingServiceLabelEnabled"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Enable" stepKey="selectAdvancedReportingServiceEnabled"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustryLabel}}" userInput="Industry" stepKey="seeAdvancedReportingIndustryLabel"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustry}}" userInput="Apps and Games" stepKey="selectAdvancedReportingIndustry"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveConfigButton1"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the configuration." stepKey="seeSuccess"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Enable" stepKey="seeAdvancedReportingServiceEnabled"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingServiceStatus}}" userInput="Subscription status: Pending" stepKey="seeAdvancedReportingServiceStatusEnabled"/> <!--Disable Advanced Reporting--> - <see stepKey="seeAdvancedReportingServiceLabelDisabled" selector="{{AdminConfigSection.advancedReportingServiceLabel}}" userInput="Advanced Reporting Service"/> - <selectOption stepKey="selectAdvancedReportingServiceDisabled" selector="{{AdminConfigSection.advancedReportingService}}" userInput="Disable"/> - <click stepKey="clickSaveConfigButtonDisabled" selector="{{AdminConfigSection.saveButton}}"/> - <see stepKey="seeSaveConfigurationMessageDisabled" selector="{{AdminConfigSection.advancedReportingSuccessMessage}}" userInput="You saved the configuration."/> - <see stepKey="seeAdvancedReportingServiceDisabled" selector="{{AdminConfigSection.advancedReportingService}}" userInput="Disable"/> - <see stepKey="seeAdvancedReportingServiceStatusDisabled" selector="{{AdminConfigSection.advancedReportingServiceStatus}}" userInput="Subscription status: Disabled"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingServiceLabel}}" userInput="Advanced Reporting Service" stepKey="seeAdvancedReportingServiceLabelDisabled"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Disable" stepKey="selectAdvancedReportingServiceDisabled"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveConfigButton2"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the configuration." stepKey="seeSuccess2"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Disable" stepKey="seeAdvancedReportingServiceDisabled"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingServiceStatus}}" userInput="Subscription status: Disabled" stepKey="seeAdvancedReportingServiceStatusDisabled"/> </test> </tests> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml index dcfdca9e8edd7..bb682c4468012 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml @@ -20,12 +20,11 @@ </annotations> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> - - <amOnPage stepKey="amOnAdminConfig" url="{{AdminConfigPage.url}}"/> - <click stepKey="clickAdvancedReportingConfigMenu" selector="{{AdminConfigSection.advancedReportingMenuItem}}"/> - <see stepKey="seeAdvancedReportingIndustryLabel" selector="{{AdminConfigSection.advancedReportingIndustryLabel}}" userInput="Industry"/> - <selectOption stepKey="selectAdvancedReportingIndustry" selector="{{AdminConfigSection.advancedReportingIndustry}}" userInput="Apps and Games"/> - <click stepKey="clickSaveConfigButton" selector="{{AdminConfigSection.saveButton}}"/> - <see stepKey="seeIndustrySuccessMessage" selector="{{AdminConfigSection.advancedReportingSuccessMessage}}" userInput="You saved the configuration."/> + <amOnPage url="{{AdminConfigGeneralAnalyticsPage.url}}" stepKey="amOnAdminConfig"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Enable" stepKey="selectAdvancedReportingServiceEnabled"/> + <see selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustryLabel}}" userInput="Industry" stepKey="seeAdvancedReportingIndustryLabel"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustry}}" userInput="Apps and Games" stepKey="selectAdvancedReportingIndustry"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveConfigButton"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the configuration." stepKey="seeSuccess"/> </test> </tests> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml index 5414e9c2a5c18..58e809ec45c4a 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml @@ -19,44 +19,47 @@ <group value="analytics"/> </annotations> <before> - <createData stepKey="noReportUserRole" entity="adminNoReportRole"/> - <createData stepKey="noReportUser" entity="adminNoReport"/> + <createData entity="adminNoReportRole" stepKey="noReportUserRole"/> + <createData entity="adminNoReport" stepKey="noReportUser"/> + <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> </before> <after> - <amOnPage stepKey="amOnLogoutPage" url="admin/admin/auth/logout/"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> </after> - <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> + <amOnPage url="{{AdminUsersPage.url}}" stepKey="amOnAdminUsersPage"/> + <fillField selector="{{AdminUserGridSection.usernameFilterTextField}}" userInput="$$noReportUser.username$$" stepKey="fillUsernameSearch"/> + <click selector="{{AdminUserGridSection.searchButton}}" stepKey="clickSearchButton"/> + <waitForPageLoad time="10" stepKey="wait1"/> + <see selector="{{AdminUserGridSection.usernameInFirstRow}}" userInput="$$noReportUser.username$$" stepKey="seeFoundUsername"/> + <click selector="{{AdminUserGridSection.searchResultFirstRow}}" stepKey="clickFoundUsername"/> + <waitForPageLoad time="30" stepKey="wait2"/> + <seeInField selector="{{AdminEditUserSection.usernameTextField}}" userInput="$$noReportUser.username$$" stepKey="seeUsernameInField"/> + <fillField selector="{{AdminEditUserSection.currentPasswordField}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}" stepKey="fillCurrentPassword"/> + <click selector="{{AdminEditUserSection.userRoleTab}}" stepKey="clickUserRoleTab"/> - <amOnPage stepKey="amOnAdminUsersPage" url="{{AdminUsersPage.url}}"/> - <fillField stepKey="fillUsernameSearch" selector="{{AdminUserGridSection.usernameFilterTextField}}" userInput="$$noReportUser.username$$"/> - <click stepKey="clickSearchButton" selector="{{AdminUserGridSection.searchButton}}"/> - <waitForPageLoad stepKey="wait1" time="10"/> - <see stepKey="seeFoundUsername" selector="{{AdminUserGridSection.usernameInFirstRow}}" userInput="$$noReportUser.username$$"/> - <click stepKey="clickFoundUsername" selector="{{AdminUserGridSection.searchResultFirstRow}}"/> - <waitForPageLoad stepKey="wait2" time="30"/> - <seeInField stepKey="seeUsernameInField" selector="{{AdminEditUserSection.usernameTextField}}" userInput="$$noReportUser.username$$"/> - <fillField stepKey="fillCurrentPassword" selector="{{AdminEditUserSection.currentPasswordField}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> - <click stepKey="clickUserRoleTab" selector="{{AdminEditUserSection.userRoleTab}}"/> + <fillField selector="{{AdminEditUserSection.roleNameFilterTextField}}" userInput="$$noReportUserRole.rolename$$" stepKey="fillRoleNameSearch"/> + <click selector="{{AdminEditUserSection.searchButton}}" stepKey="clickSearchButtonUserRole"/> + <waitForPageLoad time="10" stepKey="wait3"/> + <see selector="{{AdminEditUserSection.roleNameInFirstRow}}" userInput="$$noReportUserRole.rolename$$" stepKey="seeFoundRoleName"/> + <click selector="{{AdminEditUserSection.searchResultFirstRow}}" stepKey="clickFoundRoleName"/> + <click selector="{{AdminEditUserSection.saveButton}}" stepKey="clickSaveButton"/> + <waitForPageLoad time="10" stepKey="wait4"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the user." stepKey="seeSuccess"/> - <fillField stepKey="fillRoleNameSearch" selector="{{AdminEditUserSection.roleNameFilterTextField}}" userInput="$$noReportUserRole.rolename$$"/> - <click stepKey="clickSearchButtonUserRole" selector="{{AdminEditUserSection.searchButton}}"/> - <waitForPageLoad stepKey="wait3" time="10"/> - <see stepKey="seeFoundRoleName" selector="{{AdminEditUserSection.roleNameInFirstRow}}" userInput="$$noReportUserRole.rolename$$"/> - <click stepKey="clickFoundRoleName" selector="{{AdminEditUserSection.searchResultFirstRow}}"/> - <click stepKey="clickSaveButton" selector="{{AdminEditUserSection.saveButton}}"/> - <waitForPageLoad stepKey="wait4" time="10"/> - <see stepKey="saveUserSuccessMessage" selector="{{AdminUserGridSection.successMessage}}" userInput="You saved the user."/> + <amOnPage url="{{AdminConfigPage.url}}" stepKey="amOnAdminConfig"/> + <conditionalClick selector="{{AdminConfigSection.generalTab}}" dependentSelector="{{AdminConfigSection.generalTabOpened}}" visible="false" stepKey="openGeneralTabIfClosed"/> + <scrollTo selector="{{AdminConfigAdvancedReportingSection.advancedReportingMenuItem}}" stepKey="scrollToMenuItem"/> + <!--<see stepKey="seeAdvancedReportingConfigMenuItem" selector="{{AdminConfigAdvancedReportingSection.advancedReportingMenuItem}}" userInput="Advanced Reporting"/>--> + <seeElementInDOM selector="{{AdminConfigAdvancedReportingSection.advancedReportingMenuItem}}" stepKey="seeAdvancedReportingConfigMenuItem"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin2"/> - <amOnPage stepKey="amOnAdminConfig" url="{{AdminConfigPage.url}}"/> - <see stepKey="seeAdvancedReportingConfigMenuItem" selector="{{AdminConfigSection.advancedReportingMenuItem}}" userInput="Advanced Reporting"/> - <amOnPage stepKey="amOnLogoutPage2" url="admin/admin/auth/logout/"/> - - <amOnPage stepKey="amOnAdminLoginPage" url="{{AdminLoginPage.url}}"/> - <fillField stepKey="fillUsernameNoReport" selector="{{AdminLoginFormSection.username}}" userInput="$$noReportUser.username$$"/> - <fillField stepKey="fillPasswordNoReport" selector="{{AdminLoginFormSection.password}}" userInput="$$noReportUser.password$$"/> - <click stepKey="clickOnSignIn2" selector="{{AdminLoginFormSection.signIn}}"/> - <waitForPageLoad stepKey="wait5" time="10"/> - <amOnPage stepKey="amOnAdminConfig2" url="{{AdminConfigPage.url}}"/> - <dontSee stepKey="dontSeeAdvancedReportingConfigMenuItem" selector="{{AdminConfigSection.advancedReportingMenuItem}}" userInput="Advanced Reporting"/> + <amOnPage url="{{AdminLoginPage.url}}" stepKey="amOnAdminLoginPage"/> + <fillField selector="{{AdminLoginFormSection.username}}" userInput="$$noReportUser.username$$" stepKey="fillUsernameNoReport"/> + <fillField selector="{{AdminLoginFormSection.password}}" userInput="$$noReportUser.password$$" stepKey="fillPasswordNoReport"/> + <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickOnSignIn2"/> + <waitForPageLoad time="10" stepKey="wait5"/> + <amOnPage url="{{AdminConfigPage.url}}" stepKey="amOnAdminConfig2"/> + <conditionalClick selector="{{AdminConfigSection.generalTab}}" dependentSelector="{{AdminConfigSection.generalTabOpened}}" visible="false" stepKey="openGeneralTabIfClosed2"/> + <dontSeeElementInDOM selector="{{AdminConfigAdvancedReportingSection.advancedReportingMenuItem}}" stepKey="dontSeeAdvancedReportingConfigMenuItem"/> </test> </tests> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml index 3f17df108b50b..9dc967971f63a 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml @@ -19,17 +19,15 @@ <group value="analytics"/> </annotations> <after> - <amOnPage stepKey="amOnLogoutPage" url="admin/admin/auth/logout/"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> </after> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> - <amOnPage stepKey="amOnAdminConfig" url="{{AdminConfigPage.url}}"/> - <waitForPageLoad stepKey="waitForAdminConfig"/> - <click stepKey="clickAdvancedReportingConfigMenu" selector="{{AdminConfigSection.advancedReportingMenuItem}}"/> - <selectOption stepKey="selectAdvancedReportingIndustry" selector="{{AdminConfigSection.advancedReportingIndustry}}" userInput="Apps and Games"/> - <selectOption stepKey="selectAdvancedReportingHour" selector="{{AdminConfigSection.advancedReportingHour}}" userInput="11"/> - <selectOption stepKey="selectAdvancedReportingMinute" selector="{{AdminConfigSection.advancedReportingMinute}}" userInput="11"/> - <selectOption stepKey="selectAdvancedReportingSeconds" selector="{{AdminConfigSection.advancedReportingSeconds}}" userInput="00"/> - <click stepKey="clickSaveConfigButton" selector="{{AdminConfigSection.saveButton}}"/> - <see stepKey="seeBlankIndustryErrorMessage" selector="{{AdminConfigSection.advancedReportingSuccessMessage}}" userInput="You saved the configuration."/> + <amOnPage url="{{AdminConfigGeneralAnalyticsPage.url}}" stepKey="amOnAdminConfig"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustry}}" userInput="Apps and Games" stepKey="selectAdvancedReportingIndustry"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingHour}}" userInput="11" stepKey="selectAdvancedReportingHour"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingMinute}}" userInput="11" stepKey="selectAdvancedReportingMinute"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingSeconds}}" userInput="00" stepKey="selectAdvancedReportingSeconds"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveConfigButton"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the configuration." stepKey="seeSuccess"/> </test> </tests> diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml index 114c79189101a..2b5d60bea24e1 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml @@ -65,7 +65,7 @@ <actionGroup ref="StorefrontFillCartDataActionGroup" stepKey="StorefrontFillCartDataActionGroup"/> <waitForPageLoad stepKey="waitForPageLoad4"/> <!--Place order--> - <click selector="{{BraintreeConfigurationPaymentSection.paymentMethodContainer}} {{CheckoutPaymentSection.placeOrder}}" + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="PlaceOrder"/> <waitForPageLoad stepKey="waitForPageLoad5"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml index a4bd507d98f55..a748635ac9a53 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml @@ -129,8 +129,8 @@ <waitForPageLoad stepKey="waitForCategoryPageLoad1"/> <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewOption('Default Store View')}}" stepKey="clickStoreView"/> - <waitForElement selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" - stepKey="waitForModalAccept"/> + <waitForElementVisible selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" + stepKey="waitForPopup1"/> <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" stepKey="clickActionAccept"/> <waitForElementNotVisible selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" stepKey="waitForNotVisibleModalAccept"/> @@ -152,8 +152,8 @@ <waitForPageLoad stepKey="waitForCategoryPageLoad3"/> <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewOption('secondStoreView')}}" stepKey="clickStoreView1"/> - <waitForElement selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" - stepKey="waitForModalAccept1"/> + <waitForElementVisible selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" + stepKey="waitForPopup2"/> <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" stepKey="clickActionAccept1"/> <waitForElementNotVisible selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml index 6b444f1f6663b..c845a27773170 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml @@ -103,12 +103,15 @@ <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($createProduct.name$)}}" userInput="Jan 1, 2018" stepKey="seeProductOptionDateAndTimeInput" /> <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($createProduct.name$)}}" userInput="1/1/18, 1:00 AM" stepKey="seeProductOptionDataInput" /> <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($createProduct.name$)}}" userInput="1:00 AM" stepKey="seeProductOptionTimeInput" /> - + <!--Select shipping method--> + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShippingMethod"/> + <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> - + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskAfterClickNext"/> + <!--Select payment method--> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> <!-- Place Order --> - - <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <waitForElementVisible selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/> @@ -119,6 +122,7 @@ <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnOrdersPage"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearGridFilter"/> <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnSearch"/> @@ -141,6 +145,7 @@ <!-- Reorder and Checking the correctness of displayed custom options for user parameters on Order and correctness of displayed price Subtotal--> <click selector="{{AdminOrderDetailsMainActionsSection.reorder}}" stepKey="clickReorder"/> + <actionGroup ref="AdminCheckoutSelectCheckMoneyOrderBillingMethodActionGroup" stepKey="selectBillingMethod"/> <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="trySubmitOrder"/> <see selector="{{AdminOrderItemsOrderedSection.productNameOptions}}" userInput="{{ProductOptionField.title}}" stepKey="seeAdminOrderProductOptionField1" /> @@ -179,4 +184,4 @@ <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> </test> -</tests> \ No newline at end of file +</tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml index a03636e52ee97..fcdb92d71f1f8 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml @@ -71,11 +71,17 @@ <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($$createProduct.name$$)}}" userInput="{{ProductOptionValueDropdownLongTitle1.title}}" stepKey="seeProductOptionValueDropdown1Input1"/> + <!--Select shipping method--> + + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShippingMethod"/> + <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskAfterClickNext"/> <!-- Place Order --> - <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> + <waitForElementVisible selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/> @@ -86,6 +92,7 @@ <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnOrdersPage"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearGridFilter"/> <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnSearch"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AdminCheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AdminCheckoutActionGroup.xml new file mode 100644 index 0000000000000..a29564b2457a9 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AdminCheckoutActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!-- Checkout select Check/Money billing method --> + <actionGroup name="AdminCheckoutSelectCheckMoneyOrderBillingMethodActionGroup"> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick selector="{{AdminCheckoutPaymentSection.checkBillingMethodByName('Check / Money order')}}" dependentSelector="{{AdminCheckoutPaymentSection.checkBillingMethodByName('Check / Money order')}}" visible="true" stepKey="selectCheckmoBillingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskAfterBillingMethodSelection"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index 41b1e0d811851..1d30fcaa752a9 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -8,6 +8,12 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!-- Checkout select Flat Rate shipping method --> + <actionGroup name="CheckoutSelectFlatRateShippingMethodActionGroup"> + <conditionalClick selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" dependentSelector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" visible="true" stepKey="selectFlatRateShippingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskForNextButton"/> + </actionGroup> + <!-- Go to checkout from minicart --> <actionGroup name="GoToCheckoutFromMinicartActionGroup"> <wait stepKey="wait" time="10" /> @@ -180,8 +186,10 @@ <!-- Checkout select Check/Money Order payment --> <actionGroup name="CheckoutSelectCheckMoneyOrderPaymentActionGroup"> - <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> - <conditionalClick selector="{{CheckoutPaymentSection.checkMoneyOrderPayment}}" dependentSelector="{{CheckoutPaymentSection.billingAddress}}" visible="false" stepKey="clickCheckMoneyOrderPayment" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick selector="{{StorefrontCheckoutPaymentMethodSection.checkPaymentMethodByName('Check / Money order')}}" dependentSelector="{{StorefrontCheckoutPaymentMethodSection.checkPaymentMethodByName('Check / Money order')}}" visible="true" stepKey="selectCheckmoPaymentMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskAfterPaymentMethodSelection"/> </actionGroup> <!-- Check billing address in checkout --> @@ -228,4 +236,4 @@ <see userInput="You are signed out" stepKey="signOut"/> </actionGroup> -</actionGroups> \ No newline at end of file +</actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml index 4b5b250078ad4..d832b7941c9d7 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml @@ -84,6 +84,8 @@ <argument name="total"/> </arguments> <seeInCurrentUrl url="{{CheckoutCartPage.url}}" stepKey="assertUrl"/> + <waitForPageLoad stepKey="waitPageFullyLoaded"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> <waitForText userInput="${{total}}" selector="{{CheckoutCartSummarySection.total}}" time="30" stepKey="waitForTotal"/> <see userInput="${{subtotal}}" selector="{{CheckoutCartSummarySection.subtotal}}" stepKey="assertSubtotal"/> <see userInput="${{shipping}}" selector="{{CheckoutCartSummarySection.shipping}}" stepKey="assertShipping"/> @@ -109,4 +111,4 @@ <fillField stepKey="fillZip" selector="{{CheckoutCartSummarySection.postcode}}" userInput="{{taxCode.zip}}"/> <waitForPageLoad stepKey="waitForFormUpdate"/> </actionGroup> -</actionGroups> \ No newline at end of file +</actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/AdminCheckoutPaymentSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/AdminCheckoutPaymentSection.xml new file mode 100644 index 0000000000000..2b5dd512bc4e4 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Section/AdminCheckoutPaymentSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCheckoutPaymentSection"> + <element name="checkBillingMethodByName" type="radio" selector="//div[@id='order-billing_method']//dl[@class='admin__payment-methods']//dt//label[contains(., '{{methodName}}')]/..//input" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml index 846b20ed225dd..4a74ac8d60609 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml @@ -27,7 +27,7 @@ <element name="cartItemsArea" type="button" selector="div.block.items-in-cart"/> <element name="cartItemsAreaActive" type="textarea" selector="div.block.items-in-cart.active"/> <element name="checkMoneyOrderPayment" type="radio" selector="input#checkmo.radio" timeout="30"/> - <element name="placeOrder" type="button" selector="button.action.primary.checkout" timeout="30"/> + <element name="placeOrder" type="button" selector=".payment-method._active button.action.primary.checkout" timeout="30"/> <element name="paymentSectionTitle" type="text" selector="//*[@id='checkout-payment-method-load']//div[text()='Payment Method']" /> <element name="orderSummarySubtotal" type="text" selector="//tr[@class='totals sub']//span[@class='price']" /> <element name="orderSummaryShippingTotal" type="text" selector="//tr[@class='totals shipping excl']//span[@class='price']" /> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml new file mode 100644 index 0000000000000..c06af54f030e7 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontCheckoutPaymentMethodSection"> + <element name="billingAddress" type="text" selector=".checkout-billing-address"/> + <element name="checkPaymentMethodByName" type="radio" selector="//div[@id='checkout-payment-method-load']//div[@class='payment-method']//label//span[contains(., '{{methodName}}')]/../..//input" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest.xml index 02cc233acc7bc..f9533fd946f35 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest.xml @@ -57,6 +57,7 @@ <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnOrdersPage"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearGridFilter"/> <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnSearch"/> diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml index f4698b6865779..8a56c2777084e 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml @@ -8,5 +8,8 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminConfigSection"> <element name="saveButton" type="button" selector="#save"/> + <element name="generalTab" type="text" selector="//div[@class='admin__page-nav-title title _collapsible']//strong[text()='General']"/> + <element name="generalTabClosed" type="text" selector="//div[@class='admin__page-nav-title title _collapsible' and @aria-expanded='false' or @aria-expanded='0']//strong[text()='General']"/> + <element name="generalTabOpened" type="text" selector="//div[@class='admin__page-nav-title title _collapsible' and @aria-expanded='true' or @aria-expanded='1']//strong[text()='General']"/> </section> -</sections> \ No newline at end of file +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml index 0032a6c987e82..24266b5bcfe9f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml @@ -61,6 +61,7 @@ <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask3"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearGridFilter"/> <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="searchOrderNum"/> <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearch"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask4"/> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml index 3b741e7bf79ec..65cde53d144e7 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml @@ -92,6 +92,7 @@ <!-- Assert that taxes are applied correctly for NY --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCheckout"/> <waitForPageLoad stepKey="waitForCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> <waitForElementVisible stepKey="waitForOverviewVisible" selector="{{CheckoutPaymentSection.tax}}"/> <see stepKey="seeTax" selector="{{CheckoutPaymentSection.tax}}" userInput="$10.30"/> @@ -208,6 +209,7 @@ <!-- Assert that taxes are applied correctly for NY --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCheckout"/> <waitForPageLoad stepKey="waitForCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> <waitForElementVisible stepKey="waitForOverviewVisible" selector="{{CheckoutPaymentSection.tax}}"/> <see stepKey="seeTax" selector="{{CheckoutPaymentSection.tax}}" userInput="$8.37"/> @@ -314,6 +316,7 @@ <!-- Assert that taxes are applied correctly for CA --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCheckout"/> <waitForPageLoad stepKey="waitForCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> <waitForElementVisible stepKey="waitForOverviewVisible" selector="{{CheckoutPaymentSection.tax}}"/> <see stepKey="seeTax3" selector="{{CheckoutPaymentSection.tax}}" userInput="$10.15"/> @@ -420,6 +423,7 @@ <!-- Assert that taxes are applied correctly for NY --> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCheckout"/> <waitForPageLoad stepKey="waitForCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> <!-- Assert that taxes are applied correctly for CA --> <waitForElementVisible stepKey="waitForOverviewVisible" selector="{{CheckoutPaymentSection.tax}}"/> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php index efa75981db7bf..b97a954a981b2 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php @@ -8,6 +8,7 @@ use Magento\Bundle\Test\Fixture\BundleProduct; use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Checkout\Test\Constraint\Utils\CartPageLoadTrait; use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Page\CheckoutCart; use Magento\Mtf\Constraint\AbstractAssertForm; @@ -17,6 +18,8 @@ */ class AssertBundleProductOnConfigureCartPage extends AbstractAssertForm { + use CartPageLoadTrait; + /** * Check bundle product options correctly displayed on cart configuration page. * @@ -28,6 +31,8 @@ class AssertBundleProductOnConfigureCartPage extends AbstractAssertForm public function processAssert(CheckoutCart $checkoutCart, Cart $cart, CatalogProductView $catalogProductView) { $checkoutCart->open(); + $this->waitForCartPageLoaded($checkoutCart); + $sourceProducts = $cart->getDataFieldConfig('items')['source']; $products = $sourceProducts->getProducts(); foreach ($cart->getItems() as $key => $item) { diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php index b0e996355642a..bbe6fe293ab50 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php @@ -106,6 +106,13 @@ class Cart extends Block */ protected $cartItemClass = \Magento\Checkout\Test\Block\Cart\CartItem::class; + /** + * Locator for page with ajax loading state. + * + * @var string + */ + private $ajaxLoading = 'body.ajax-loading'; + /** * Wait for PayPal page is loaded. * @@ -273,4 +280,14 @@ public function waitForCheckoutButton() { $this->waitForElementVisible($this->inContextPaypalCheckoutButton); } + + /** + * Wait loading. + * + * @return void + */ + public function waitForLoader() + { + $this->waitForElementNotVisible($this->ajaxLoading); + } } 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 10299486a08ce..3d293700db8c9 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 @@ -72,6 +72,13 @@ class Shipping extends Form */ protected $commonShippingPriceSelector = '.totals.shipping .price'; + /** + * Estimate shipping and tax form locator. + * + * @var string + */ + private $estimateShippingForm = '#shipping-zip-form'; + /** * Open estimate shipping and tax form. * @@ -250,4 +257,51 @@ public function waitForCommonShippingPriceBlock() { $this->waitForElementVisible($this->commonShippingPriceSelector, Locator::SELECTOR_CSS); } + + /** + * Wait until estimation form to appear. + * + * @return void + */ + public function waitForEstimateShippingAndTaxForm() + { + $browser = $this->browser; + $selector = $this->estimateShippingForm; + + $browser->waitUntil( + function () use ($browser, $selector) { + $element = $browser->find($selector); + return $element->isPresent() ? true : null; + } + ); + } + + /** + * Wait for shipping method form. + * + * @return void + */ + public function waitForShippingMethodForm() + { + $browser = $this->browser; + $selector = $this->shippingMethodForm; + + $browser->waitUntil( + function () use ($browser, $selector) { + $element = $browser->find($selector); + return $element->isPresent() ? true : null; + } + ); + } + + /** + * Wait for summary block to be loaded. + * + * @return void + */ + public function waitForSummaryBlock() + { + $this->waitForEstimateShippingAndTaxForm(); + $this->waitForShippingMethodForm(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Totals.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Totals.php index fda29a2fe78fc..f632cdc3d7464 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Totals.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Totals.php @@ -264,4 +264,15 @@ public function waitForShippingPriceBlock() { $this->waitForElementVisible($this->shippingPriceBlockSelector, Locator::SELECTOR_CSS); } + + /** + * Wait for "Grand Total" row to appear. + * + * @return void + */ + public function waitForGrandTotal() + { + $this->waitForUpdatedTotals(); + $this->waitForElementVisible($this->grandTotal); + } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php index 144e41dca0d92..b0ed9d358f93a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php @@ -7,6 +7,7 @@ namespace Magento\Checkout\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogProductSimple; +use Magento\Checkout\Test\Constraint\Utils\CartPageLoadTrait; use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Fixture\Cart\Items; use Magento\Checkout\Test\Page\CheckoutCart; @@ -21,6 +22,8 @@ */ class AssertCartItemsOptions extends AbstractAssertForm { + use CartPageLoadTrait; + /** * Error message for verify options * @@ -44,6 +47,8 @@ class AssertCartItemsOptions extends AbstractAssertForm public function processAssert(CheckoutCart $checkoutCart, Cart $cart) { $checkoutCart->open(); + $this->waitForCartPageLoaded($checkoutCart); + /** @var Items $sourceProducts */ $sourceProducts = $cart->getDataFieldConfig('items')['source']; $products = $sourceProducts->getProducts(); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php index 9bedda350d065..432bbd4f2146e 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php @@ -6,6 +6,7 @@ namespace Magento\Checkout\Test\Constraint; +use Magento\Checkout\Test\Constraint\Utils\CartPageLoadTrait; use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Page\CheckoutCart; use Magento\Mtf\Constraint\AbstractConstraint; @@ -16,6 +17,8 @@ */ class AssertGrandTotalInShoppingCart extends AbstractConstraint { + use CartPageLoadTrait; + /** * Assert that grand total is equal to expected * @@ -28,6 +31,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, $requireRe { if ($requireReload) { $checkoutCart->open(); + $this->waitForCartPageLoaded($checkoutCart); $checkoutCart->getTotalsBlock()->waitForUpdatedTotals(); } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php index 42c79c1280e38..88d4a3e8d35ba 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php @@ -7,6 +7,7 @@ namespace Magento\Checkout\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogProductSimple; +use Magento\Checkout\Test\Constraint\Utils\CartPageLoadTrait; use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Fixture\Cart\Items; use Magento\Checkout\Test\Page\CheckoutCart; @@ -19,6 +20,8 @@ */ class AssertPriceInShoppingCart extends AbstractAssertForm { + use CartPageLoadTrait; + /** * Assert that price in the shopping cart equals to expected price from data set * @@ -29,6 +32,8 @@ class AssertPriceInShoppingCart extends AbstractAssertForm public function processAssert(CheckoutCart $checkoutCart, Cart $cart) { $checkoutCart->open(); + $this->waitForCartPageLoaded($checkoutCart); + /** @var Items $sourceProducts */ $sourceProducts = $cart->getDataFieldConfig('items')['source']; $products = $sourceProducts->getProducts(); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php index 40eb41e127245..b80b4c85227c0 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php @@ -7,6 +7,7 @@ namespace Magento\Checkout\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogProductSimple; +use Magento\Checkout\Test\Constraint\Utils\CartPageLoadTrait; use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Fixture\Cart\Items; use Magento\Checkout\Test\Page\CheckoutCart; @@ -19,6 +20,8 @@ */ class AssertProductQtyInShoppingCart extends AbstractAssertForm { + use CartPageLoadTrait; + /** * Assert that quantity in the shopping cart is equals to expected quantity from data set * @@ -29,6 +32,8 @@ class AssertProductQtyInShoppingCart extends AbstractAssertForm public function processAssert(CheckoutCart $checkoutCart, Cart $cart) { $checkoutCart->open(); + $this->waitForCartPageLoaded($checkoutCart); + /** @var Items $sourceProducts */ $sourceProducts = $cart->getDataFieldConfig('items')['source']; $products = $sourceProducts->getProducts(); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php index 2ee9caa251a74..5e743e735d42f 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php @@ -7,6 +7,7 @@ namespace Magento\Checkout\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogProductSimple; +use Magento\Checkout\Test\Constraint\Utils\CartPageLoadTrait; use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Fixture\Cart\Items; use Magento\Checkout\Test\Page\CheckoutCart; @@ -19,6 +20,8 @@ */ class AssertSubtotalInShoppingCart extends AbstractAssertForm { + use CartPageLoadTrait; + /** * Assert that subtotal total in the shopping cart is equals to expected total from data set * @@ -31,6 +34,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, $requireRe { if ($requireReload) { $checkoutCart->open(); + $this->waitForCartPageLoaded($checkoutCart); } /** @var Items $sourceProducts */ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/Utils/CartPageLoadTrait.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/Utils/CartPageLoadTrait.php new file mode 100644 index 0000000000000..fa349554fa139 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/Utils/CartPageLoadTrait.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Checkout\Test\Constraint\Utils; + +use Magento\Checkout\Test\Page\CheckoutCart; + +/** + * Check if cart page is fully loaded. + */ +trait CartPageLoadTrait +{ + /** + * @param CheckoutCart $checkoutCart + * @return void + */ + public function waitForCartPageLoaded(CheckoutCart $checkoutCart) : void + { + $checkoutCart->getCartBlock()->waitForLoader(); + if (!$checkoutCart->getCartBlock()->cartIsEmpty()) { + $checkoutCart->getShippingBlock()->waitForSummaryBlock(); + $checkoutCart->getTotalsBlock()->waitForGrandTotal(); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php index 5935a68c43c21..af267cfa30ec1 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php @@ -115,6 +115,7 @@ public function test( } else { $miniShoppingCart->getCartItem($newProduct)->clickEditItem(); $this->catalogProductView->getViewBlock()->addToCart($newProduct); + $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); } // Prepare data for asserts: $cart['data']['items'] = ['products' => [$newProduct]]; diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php index 30e790f978c42..1a4cb787bf1c7 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php @@ -102,10 +102,12 @@ public function test( $productUrl = $_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'; $browser->open($productUrl); $this->catalogProductView->getViewBlock()->addToCart($product); + $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); if ($isGuest) { $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); $browser->open($productUrl); $this->catalogProductView->getViewBlock()->addToCart($product); + $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php index 2b0bd7178cdad..91b4f711700b5 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php @@ -144,6 +144,7 @@ public function test(Customer $customer, $product) )->run(); $this->browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); $this->catalogProductView->getViewBlock()->addToCart($product); + $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); //Steps $this->customerIndex->open(); From 3de065bfeefbe324d1db903800efb6a95824e076 Mon Sep 17 00:00:00 2001 From: Rain2o <jrainwater@thinkpyxl.com> Date: Wed, 11 Jul 2018 17:29:24 -0400 Subject: [PATCH 0542/1158] Include multiselect options using custom source models --- .../Product/Indexer/Eav/Source.php | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php index 3a61e7e364454..30b49dfeda103 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php @@ -24,22 +24,29 @@ class Source extends AbstractEav */ protected $_resourceHelper; - /** - * Construct - * - * @param \Magento\Framework\Model\ResourceModel\Db\Context $context - * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy - * @param \Magento\Eav\Model\Config $eavConfig - * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper - * @param null|string $connectionName - */ + /** + * @var \Magento\Eav\Api\AttributeRepositoryInterface + */ + protected $_attributeRepository; + + /** + * Construct + * + * @param \Magento\Framework\Model\ResourceModel\Db\Context $context + * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy + * @param \Magento\Eav\Model\Config $eavConfig + * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper + * @param \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository + * @param null|string $connectionName + */ public function __construct( \Magento\Framework\Model\ResourceModel\Db\Context $context, \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper, + \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository, $connectionName = null ) { parent::__construct( @@ -50,6 +57,7 @@ public function __construct( $connectionName ); $this->_resourceHelper = $resourceHelper; + $this->_attributeRepository = $attributeRepository; } /** @@ -234,6 +242,9 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu $options[$row['attribute_id']][$row['option_id']] = true; } + // Include custom source model options + $options = $this->_getMultiSelectAttributeWithSourceModels($attrIds, $options); + // prepare get multiselect values query $productValueExpression = $connection->getCheckSql('pvs.value_id > 0', 'pvs.value', 'pvd.value'); $select = $connection->select()->from( @@ -297,6 +308,46 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu return $this; } + /** + * Get options for multiselect attributes using custom source models + * @maderlock's fix from: https://github.com/magento/magento2/issues/417#issuecomment-265146285 + * + * @param array $attrIds + * @param array $options + * + * @return array + * @throws \Zend_Db_Statement_Exception + */ + protected function _getMultiSelectAttributeWithSourceModels( $attrIds, $options ) { + // Add options from custom source models + $select = $this->getConnection()->select() + ->from( + ['ea' => $this->getTable('eav_attribute')], + ['attribute_id','entity_type_id', 'attribute_code'] + ) + ->where('attribute_id IN(?)', $attrIds) + ->where('source_model is not null'); + $query = $select->query(); + + while ($row = $query->fetch()) { + try { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ + $attribute = $this->_attributeRepository->get($row['entity_type_id'], $row['attribute_code']); + $sourceModelOptions = $attribute->getOptions(); + // Add options to list used below + foreach ($sourceModelOptions as $o) { + $options[$row['attribute_id']][$o->getValue()] = true; + } + } catch (\BadMethodCallException $e) { + // Skip + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + // skip + } + } + + return $options; + } + /** * Save a data to temporary source index table * From c6352c6c9166eba48d86852774b876ecaf34ebd8 Mon Sep 17 00:00:00 2001 From: Rain2o <jrainwater@thinkpyxl.com> Date: Thu, 12 Jul 2018 10:34:35 -0400 Subject: [PATCH 0543/1158] Fixed PHP sniffer errors. --- .../Product/Indexer/Eav/Source.php | 113 +++++++++--------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php index 30b49dfeda103..ab09171a6f2ed 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php @@ -24,29 +24,29 @@ class Source extends AbstractEav */ protected $_resourceHelper; - /** - * @var \Magento\Eav\Api\AttributeRepositoryInterface - */ + /** + * @var \Magento\Eav\Api\AttributeRepositoryInterface + */ protected $_attributeRepository; - /** - * Construct - * - * @param \Magento\Framework\Model\ResourceModel\Db\Context $context - * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy - * @param \Magento\Eav\Model\Config $eavConfig - * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper - * @param \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository - * @param null|string $connectionName - */ + /** + * Construct + * + * @param \Magento\Framework\Model\ResourceModel\Db\Context $context + * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy + * @param \Magento\Eav\Model\Config $eavConfig + * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper + * @param \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository + * @param null|string $connectionName + */ public function __construct( \Magento\Framework\Model\ResourceModel\Db\Context $context, \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper, - \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository, + \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository, $connectionName = null ) { parent::__construct( @@ -242,8 +242,8 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu $options[$row['attribute_id']][$row['option_id']] = true; } - // Include custom source model options - $options = $this->_getMultiSelectAttributeWithSourceModels($attrIds, $options); + // Include custom source model options + $options = $this->_getMultiSelectAttributeWithSourceModels($attrIds, $options); // prepare get multiselect values query $productValueExpression = $connection->getCheckSql('pvs.value_id > 0', 'pvs.value', 'pvd.value'); @@ -308,45 +308,46 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu return $this; } - /** - * Get options for multiselect attributes using custom source models - * @maderlock's fix from: https://github.com/magento/magento2/issues/417#issuecomment-265146285 - * - * @param array $attrIds - * @param array $options - * - * @return array - * @throws \Zend_Db_Statement_Exception - */ - protected function _getMultiSelectAttributeWithSourceModels( $attrIds, $options ) { - // Add options from custom source models - $select = $this->getConnection()->select() - ->from( - ['ea' => $this->getTable('eav_attribute')], - ['attribute_id','entity_type_id', 'attribute_code'] - ) - ->where('attribute_id IN(?)', $attrIds) - ->where('source_model is not null'); - $query = $select->query(); - - while ($row = $query->fetch()) { - try { - /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ - $attribute = $this->_attributeRepository->get($row['entity_type_id'], $row['attribute_code']); - $sourceModelOptions = $attribute->getOptions(); - // Add options to list used below - foreach ($sourceModelOptions as $o) { - $options[$row['attribute_id']][$o->getValue()] = true; - } - } catch (\BadMethodCallException $e) { - // Skip - } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { - // skip - } - } - - return $options; - } + /** + * Get options for multiselect attributes using custom source models + * @maderlock's fix from: https://github.com/magento/magento2/issues/417#issuecomment-265146285 + * + * @param array $attrIds + * @param array $options + * + * @return array + * @throws \Zend_Db_Statement_Exception + */ + protected function _getMultiSelectAttributeWithSourceModels($attrIds, $options) + { + // Add options from custom source models + $select = $this->getConnection()->select() + ->from( + ['ea' => $this->getTable('eav_attribute')], + ['attribute_id','entity_type_id', 'attribute_code'] + ) + ->where('attribute_id IN(?)', $attrIds) + ->where('source_model is not null'); + $query = $select->query(); + + while ($row = $query->fetch()) { + try { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ + $attribute = $this->_attributeRepository->get($row['entity_type_id'], $row['attribute_code']); + $sourceModelOptions = $attribute->getOptions(); + // Add options to list used below + foreach ($sourceModelOptions as $o) { + $options[$row['attribute_id']][$o->getValue()] = true; + } + } catch (\BadMethodCallException $e) { + // Skip + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + // skip + } + } + + return $options; + } /** * Save a data to temporary source index table From cb69dcc551dd99d0bd7c1829c420d796d77847ec Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Thu, 8 Nov 2018 16:05:07 +0200 Subject: [PATCH 0544/1158] MAGETWO-95829: Product positions are incorrect after import - Fixed to correct zero position during product import process - Fixed to correct sorting position on admin Category edit page --- .../Magento/Catalog/Model/Category/Product/PositionResolver.php | 2 ++ .../Test/Unit/Model/Category/Product/PositionResolverTest.php | 2 +- app/code/Magento/CatalogImportExport/Model/Import/Product.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php b/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php index 1e07c0cdd924e..44bf153f83697 100644 --- a/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php +++ b/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php @@ -43,6 +43,8 @@ public function getPositions(int $categoryId): array $categoryId )->order( 'ccp.position ' . \Magento\Framework\DB\Select::SQL_ASC + )->order( + 'ccp.product_id ' . \Magento\Framework\DB\Select::SQL_DESC ); return array_flip($connection->fetchCol($select)); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php index 1ff3a1bae5c28..7ad8b1a0ab3f8 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php @@ -107,7 +107,7 @@ public function testGetPositions() $this->select->expects($this->once()) ->method('where') ->willReturnSelf(); - $this->select->expects($this->once()) + $this->select->expects($this->exactly(2)) ->method('order') ->willReturnSelf(); $this->select->expects($this->once()) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 6f8b2248d8d89..ce699b73131f1 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1423,7 +1423,7 @@ protected function _saveProductCategories(array $categoriesData) $delProductId[] = $productId; foreach (array_keys($categories) as $categoryId) { - $categoriesIn[] = ['product_id' => $productId, 'category_id' => $categoryId, 'position' => 1]; + $categoriesIn[] = ['product_id' => $productId, 'category_id' => $categoryId, 'position' => 0]; } } if (Import::BEHAVIOR_APPEND != $this->getBehavior()) { From 7bedc1a87767a148468586906eb68f76fae84a94 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov <sidolov@magento.com> Date: Thu, 8 Nov 2018 16:07:46 +0200 Subject: [PATCH 0545/1158] magento-engcom/magento2ce#2316: Skipped MFTF test --- .../Test/Mftf/Test/AdminConfigurationIndustryTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml index dcfdca9e8edd7..4b18fc7b98309 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml @@ -17,6 +17,9 @@ <severity value="MAJOR"/> <testCaseId value="MAGETWO-63898"/> <group value="analytics"/> + <skip> + <issueId value="MAGETWO-96223"/> + </skip> </annotations> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> From 7b3a047c27dc072938f85f7f0c0561d56c7ffd7c Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Thu, 8 Nov 2018 16:12:44 +0200 Subject: [PATCH 0546/1158] MAGETWO-96063: [TSG] Pull Request MFTF 8 stabilization --- .../Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml index 9dc967971f63a..58e62500b8203 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml @@ -23,6 +23,7 @@ </after> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> <amOnPage url="{{AdminConfigGeneralAnalyticsPage.url}}" stepKey="amOnAdminConfig"/> + <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingService}}" userInput="Enable" stepKey="selectAdvancedReportingServiceEnabled"/> <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingIndustry}}" userInput="Apps and Games" stepKey="selectAdvancedReportingIndustry"/> <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingHour}}" userInput="11" stepKey="selectAdvancedReportingHour"/> <selectOption selector="{{AdminConfigAdvancedReportingSection.advancedReportingMinute}}" userInput="11" stepKey="selectAdvancedReportingMinute"/> From f9acb655f01565c58d1df26643b4446407c4eb0a Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 8 Nov 2018 15:18:58 +0100 Subject: [PATCH 0547/1158] Added a separate resolver for returning category products count --- app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php | 1 - .../Magento/CatalogGraphQl/Model/Resolver/Category/Products.php | 2 +- app/code/Magento/CatalogGraphQl/etc/schema.graphqls | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php b/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php index f0cdab9498abb..e783c749fdc6e 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php @@ -52,7 +52,6 @@ public function hydrateCategory(Category $category, $basicFieldsOnly = false) : $categoryData = $category->getData(); } else { $categoryData = $this->dataObjectProcessor->buildOutputDataArray($category, CategoryInterface::class); - $categoryData['product_count'] = $category->getProductCount(); } $categoryData['id'] = $category->getId(); $categoryData['children'] = []; diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php index 557c7e08ff432..59c21b6b0109d 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php @@ -65,7 +65,7 @@ public function resolve( 'eq' => $value['id'] ] ]; - $searchCriteria = $this->searchCriteriaBuilder->build($field->getName(), $args); + $searchCriteria = $this->searchCriteriaBuilder->build($field->getName(), $args); $searchCriteria->setCurrentPage($args['currentPage']); $searchCriteria->setPageSize($args['pageSize']); $searchResult = $this->filterQuery->getResult($searchCriteria, $info); diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 5d62cb63f1662..7f31266ebf266 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -379,7 +379,7 @@ interface CategoryInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model level: Int @doc(description: "Indicates the depth of the category within the tree") created_at: String @doc(description: "Timestamp indicating when the category was created") updated_at: String @doc(description: "Timestamp indicating when the category was updated") - product_count: Int @doc(description: "The number of products in the category") + product_count: Int @doc(description: "The number of products in the category") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\ProductsCount") default_sort_by: String @doc(description: "The attribute to use for sorting") products( pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), From 9aacf0e0f9044c133786de725fbe5d926c0223d5 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 8 Nov 2018 15:29:11 +0100 Subject: [PATCH 0548/1158] Missing resolver added --- .../Model/Resolver/Category/Products.php | 2 +- .../Model/Resolver/Category/ProductsCount.php | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Category/ProductsCount.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php index 59c21b6b0109d..557c7e08ff432 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/Products.php @@ -65,7 +65,7 @@ public function resolve( 'eq' => $value['id'] ] ]; - $searchCriteria = $this->searchCriteriaBuilder->build($field->getName(), $args); + $searchCriteria = $this->searchCriteriaBuilder->build($field->getName(), $args); $searchCriteria->setCurrentPage($args['currentPage']); $searchCriteria->setPageSize($args['pageSize']); $searchResult = $this->filterQuery->getResult($searchCriteria, $info); diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/ProductsCount.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/ProductsCount.php new file mode 100644 index 0000000000000..397fd12b7e714 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/ProductsCount.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Category; + +use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Product\Visibility; +use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product\CollectionProcessor\StockProcessor; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; + +/** + * Retrieves products count for a category + */ +class ProductsCount implements ResolverInterface +{ + /** + * @var Visibility + */ + private $catalogProductVisibility; + + /** + * @var StockProcessor + */ + private $stockProcessor; + + /** + * @var SearchCriteriaInterface + */ + private $searchCriteria; + + /** + * @param Visibility $catalogProductVisibility + * @param SearchCriteriaInterface $searchCriteria + * @param StockProcessor $stockProcessor + */ + public function __construct( + Visibility $catalogProductVisibility, + SearchCriteriaInterface $searchCriteria, + StockProcessor $stockProcessor + ) { + $this->catalogProductVisibility = $catalogProductVisibility; + $this->searchCriteria = $searchCriteria; + $this->stockProcessor = $stockProcessor; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($value['model'])) { + throw new GraphQlInputException(__('"model" value should be specified')); + } + /** @var Category $category */ + $category = $value['model']; + $productsCollection = $category->getProductCollection(); + $productsCollection->setVisibility($this->catalogProductVisibility->getVisibleInSiteIds()); + $productsCollection = $this->stockProcessor->process($productsCollection, $this->searchCriteria, []); + + return $productsCollection->getSize(); + } +} From 53e6f67300259358f6e533c3eed8e0e939ca782f Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Thu, 8 Nov 2018 16:29:40 +0200 Subject: [PATCH 0549/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - add minor changes to test --- ...raintreeFill.xml => AdminOrderBraintreeFillActionGroup.xml} | 3 +-- ...etateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) rename app/code/Magento/Braintree/Test/Mftf/ActionGroup/{AdminOrderBraintreeFill.xml => AdminOrderBraintreeFillActionGroup.xml} (97%) diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFillActionGroup.xml similarity index 97% rename from app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml rename to app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFillActionGroup.xml index 6ef70b1f38660..c2e6af9dcd735 100644 --- a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFill.xml +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminOrderBraintreeFillActionGroup.xml @@ -8,8 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminOrderBraintreeFill"> - + <actionGroup name="AdminOrderBraintreeFillActionGroup"> <!--Select Braintree Payment method on Admin Order Create Page--> <click stepKey="chooseBraintree" selector="{{NewOrderSection.creditCardBraintree}}"/> <waitForPageLoad stepKey="waitForBraintreeConfigs" time="5"/> diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml index 470c425f3dae1..a7c0e8f62544e 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml @@ -92,7 +92,7 @@ <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> <!--Select Braintree online Payment method --> - <actionGroup ref="AdminOrderBraintreeFill" stepKey="selectCreditCardPayment"/> + <actionGroup ref="AdminOrderBraintreeFillActionGroup" stepKey="selectCreditCardPayment"/> <!--Submit Order--> <click stepKey="submitOrder" selector="{{NewOrderSection.submitOrder}}"/> From c713b675dc4c473d9d001ec2ade980aeeaf254f3 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 8 Nov 2018 15:39:28 +0100 Subject: [PATCH 0550/1158] Added test for setting shipping methods as guest for a customer cart --- .../Quote/SetShippingMethodOnCartTest.php | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php index 932c8ac386c27..7e77284c6b220 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/SetShippingMethodOnCartTest.php @@ -161,7 +161,35 @@ public function testSetShippingMethodWithNonExistingAddress() $this->sendRequestWithToken($query); } - // TODO: TBD - add check for guest with attempt to set shipping method to the customer's shopping cart + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetShippingMethodByGuestToCustomerCart() + { + $shippingCarrierCode = 'flatrate'; + $shippingMethodCode = 'flatrate'; + $this->quoteResource->load( + $this->quote, + 'test_order_1', + 'reserved_order_id' + ); + $shippingAddress = $this->quote->getShippingAddress(); + $shippingAddressId = $shippingAddress->getId(); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId()); + + $query = $this->prepareMutationQuery( + $maskedQuoteId, + $shippingMethodCode, + $shippingCarrierCode, + $shippingAddressId + ); + + self::expectExceptionMessage( + "The current user cannot perform operations on cart \"$maskedQuoteId\"" + ); + + $this->graphQlQuery($query); + } /** * Generates query for setting the specified shipping method on cart From 9b853a7303093342c2a29a17f3029da4428f8839 Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Mon, 5 Nov 2018 15:42:06 -0600 Subject: [PATCH 0551/1158] MAGETWO-95906: Sales rules sets default time using UTC timezone when left empty --- .../Page/AdminConfigurationStoresPage.xml | 3 + .../Mftf/Section/LocaleOptionsSection.xml | 15 +++ .../StorefrontProductCartActionGroup.xml | 2 +- .../Controller/Adminhtml/Promo/Quote/Save.php | 38 ++++++- ...inCreateCartPriceRuleEmptyFromDateTest.xml | 104 ++++++++++++++++++ 5 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Backend/Test/Mftf/Section/LocaleOptionsSection.xml create mode 100644 app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml index d1bf3c2cb2ed6..8afc2c5bbb32f 100644 --- a/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml +++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml @@ -14,4 +14,7 @@ <page name="WebConfigurationPage" url="admin/system_config/edit/section/web/" area="admin" module="Backend"> <section name="WYSIWYGOptionsSection"/> </page> + <page name="GeneralConfigurationPage" url="admin/system_config/edit/section/general/" area="admin" module="Backend"> + <section name="LocaleOptionsSection"/> + </page> </pages> diff --git a/app/code/Magento/Backend/Test/Mftf/Section/LocaleOptionsSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/LocaleOptionsSection.xml new file mode 100644 index 0000000000000..c50bf0664f9cb --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/Section/LocaleOptionsSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="LocaleOptionsSection"> + <element name="sectionHeader" type="text" selector="#general_locale-head"/> + <element name="timezone" type="select" selector="#general_locale_timezone"/> + </section> +</sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml index 4b5b250078ad4..1473618ceeb34 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml @@ -86,8 +86,8 @@ <seeInCurrentUrl url="{{CheckoutCartPage.url}}" stepKey="assertUrl"/> <waitForText userInput="${{total}}" selector="{{CheckoutCartSummarySection.total}}" time="30" stepKey="waitForTotal"/> <see userInput="${{subtotal}}" selector="{{CheckoutCartSummarySection.subtotal}}" stepKey="assertSubtotal"/> - <see userInput="${{shipping}}" selector="{{CheckoutCartSummarySection.shipping}}" stepKey="assertShipping"/> <see userInput="({{shippingMethod}})" selector="{{CheckoutCartSummarySection.shippingMethod}}" stepKey="assertShippingMethod"/> + <waitForText userInput="${{shipping}}" selector="{{CheckoutCartSummarySection.shipping}}" time="30" stepKey="assertShipping"/> <see userInput="${{total}}" selector="{{CheckoutCartSummarySection.total}}" stepKey="assertTotal"/> </actionGroup> diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php index a5b71130e70eb..388679e6d9eff 100644 --- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php +++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php @@ -6,8 +6,41 @@ */ namespace Magento\SalesRule\Controller\Adminhtml\Promo\Quote; -class Save extends \Magento\SalesRule\Controller\Adminhtml\Promo\Quote +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; + +/** + * SalesRule save controller + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class Save extends \Magento\SalesRule\Controller\Adminhtml\Promo\Quote implements HttpPostActionInterface { + /** + * @var TimezoneInterface + */ + private $timezone; + + /** + * @param \Magento\Backend\App\Action\Context $context + * @param \Magento\Framework\Registry $coreRegistry + * @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory + * @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter + * @param TimezoneInterface $timezone + */ + public function __construct( + \Magento\Backend\App\Action\Context $context, + \Magento\Framework\Registry $coreRegistry, + \Magento\Framework\App\Response\Http\FileFactory $fileFactory, + \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter, + TimezoneInterface $timezone = null + ) { + parent::__construct($context, $coreRegistry, $fileFactory, $dateFilter); + $this->timezone = $timezone ?? \Magento\Framework\App\ObjectManager::getInstance()->get( + TimezoneInterface::class + ); + } + /** * Promo quote save action * @@ -26,6 +59,9 @@ public function execute() ['request' => $this->getRequest()] ); $data = $this->getRequest()->getPostValue(); + if (empty($data['from_date'])) { + $data['from_date'] = $this->timezone->formatDate(); + } $filterValues = ['from_date' => $this->_dateFilter]; if ($this->getRequest()->getParam('to_date')) { diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml new file mode 100644 index 0000000000000..e6676dab4eb5e --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateCartPriceRuleEmptyFromDateTest"> + <annotations> + <features value="SalesRule"/> + <stories value="Create cart price rule"/> + <title value="Admin should be able to create a cart price rule with no starting date"/> + <description value="Admin should be able to create a cart price rule without specifying the from_date and it should be set with the current date"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-5299"/> + <group value="SalesRule"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="category"/> + <createData entity="SimpleProduct" stepKey="product"> + <requiredEntity createDataKey="category"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <after> + <!-- Delete the cart price rule we made during the test --> + <actionGroup ref="DeleteCartPriceRuleByName" stepKey="cleanUpRule"> + <argument name="ruleName" value="{{_defaultCoupon.code}}"/> + </actionGroup> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Set timezone--> + <!--Set timezone so we need compare with the same timezone used in "generateDate" action--> + <amOnPage url="{{GeneralConfigurationPage.url}}" stepKey="goToGeneralConfig"/> + <waitForPageLoad stepKey="waitForConfigPage"/> + <wait stepKey="wait" time="10"/> + <conditionalClick selector="{{LocaleOptionsSection.sectionHeader}}" dependentSelector="{{LocaleOptionsSection.timezone}}" visible="false" stepKey="openLocaleSection"/> + <grabValueFrom selector="{{LocaleOptionsSection.timezone}}" stepKey="originalTimezone"/> + <selectOption selector="{{LocaleOptionsSection.timezone}}" userInput="America/Los_Angeles" stepKey="setTimezone"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="saveConfig"/> + + <!-- Create a cart price rule based on a coupon code --> + <amOnPage url="{{AdminCartPriceRulesPage.url}}" stepKey="amOnCartPriceList"/> + <waitForPageLoad stepKey="waitForPriceList"/> + <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRule"/> + <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{_defaultCoupon.code}}" stepKey="fillRuleName"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="selectWebsites"/> + <actionGroup ref="selectNotLoggedInCustomerGroup" stepKey="selectCustomerGroup"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.coupon}}" userInput="Specific Coupon" stepKey="selectCouponType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.couponCode}}" userInput="{{_defaultCoupon.code}}" stepKey="fillCouponCode"/> + <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Fixed amount discount for whole cart" stepKey="selectActionType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="5" stepKey="fillDiscountAmount"/> + <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> + + <!-- Verify initial successful save --> + <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> + <fillField selector="{{AdminCartPriceRulesSection.filterByNameInput}}" userInput="{{_defaultCoupon.code}}" stepKey="filterByName"/> + <click selector="{{AdminCartPriceRulesSection.searchButton}}" stepKey="doFilter"/> + <see selector="{{AdminCartPriceRulesSection.nameColumns}}" userInput="{{_defaultCoupon.code}}" stepKey="seeRuleInResults"/> + + <!-- Verify further on the Rule's edit page --> + <click selector="{{AdminCartPriceRulesSection.rowContainingText(_defaultCoupon.code)}}" stepKey="goToEditRule"/> + <seeInField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{_defaultCoupon.code}}" stepKey="seeRuleName"/> + <seeOptionIsSelected selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="seeWebsites"/> + <seeOptionIsSelected selector="{{AdminCartPriceRulesFormSection.coupon}}" userInput="Specific Coupon" stepKey="seeCouponType"/> + <seeInField selector="{{AdminCartPriceRulesFormSection.couponCode}}" userInput="{{_defaultCoupon.code}}" stepKey="seeCouponCode"/> + <generateDate date="now" format="m/j/Y" timezone="America/Los_Angeles" stepKey="today"/> + <seeInField selector="{{AdminCartPriceRulesFormSection.fromDate}}" userInput="$today" stepKey="seeCorrectFromDate"/> + <seeInField selector="{{AdminCartPriceRulesFormSection.toDate}}" userInput="" stepKey="seeEmptyToDate"/> + <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions2"/> + <seeOptionIsSelected selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Fixed amount discount for whole cart" stepKey="seeActionType"/> + <seeInField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="5" stepKey="seeDiscountAmount"/> + + <!-- Spot check the storefront --> + <amOnPage url="$$product.custom_attributes[url_key]$$.html" stepKey="goToProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForAddToCart"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCartPage"/> + <waitForPageLoad stepKey="waitForCartPage"/> + <actionGroup ref="StorefrontApplyCouponActionGroup" stepKey="applyCoupon"> + <argument name="coupon" value="_defaultCoupon"/> + </actionGroup> + <waitForPageLoad stepKey="waitForProductPageLoad2"/> + <waitForElementVisible selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="waitForDiscountElement"/> + <see selector="{{CheckoutCartSummarySection.discountAmount}}" userInput="-$5.00" stepKey="seeDiscountTotal"/> + + <!--Reset timezone--> + <amOnPage url="{{GeneralConfigurationPage.url}}" stepKey="goToGeneralConfigReset"/> + <waitForPageLoad stepKey="waitForConfigPageReset"/> + <conditionalClick selector="{{LocaleOptionsSection.sectionHeader}}" dependentSelector="{{LocaleOptionsSection.timezone}}" visible="false" stepKey="openLocaleSectionReset"/> + <selectOption selector="{{LocaleOptionsSection.timezone}}" userInput="$originalTimezone" stepKey="resetTimezone"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="saveConfigReset"/> + </test> +</tests> From 13f4ad193092a153338418024facef621e598468 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 8 Nov 2018 08:41:45 -0600 Subject: [PATCH 0552/1158] MAGETWO-96192: Products with "Less Than", "Greater Than", "Less Than Or Equal", "Greater Than Or Equal" condition returns error on storefront - Added < and > to list of encoded characters --- .../Cms/Test/Mftf/Section/TinyMCESection.xml | 3 +++ ...oWYSIWYGWithCatalogProductListTypeTest.xml | 23 ++++++++++++++++++- .../Framework/Data/Wysiwyg/Normalizer.php | 3 ++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml b/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml index 92112661846c0..c7ea85e441bb9 100644 --- a/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml +++ b/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml @@ -98,6 +98,9 @@ <element name="AddParam" type="button" selector=".rule-param-add"/> <element name="ConditionsDropdown" type="select" selector="#conditions__1__new_child"/> <element name="RuleParam" type="button" selector="//a[text()='...']"/> + <element name="RuleParamSelect" type="select" selector="//ul[contains(@class,'rule-param-children')]/li[{{arg1}}]//*[contains(@class,'rule-param')][{{arg2}}]//select" parameterized="true"/> + <element name="RuleParamInput" type="input" selector="//ul[contains(@class,'rule-param-children')]/li[{{arg1}}]//*[contains(@class,'rule-param')][{{arg2}}]//input" parameterized="true"/> + <element name="RuleParamLabel" type="input" selector="//ul[contains(@class,'rule-param-children')]/li[{{arg1}}]//*[contains(@class,'rule-param')][{{arg2}}]//a" parameterized="true"/> <element name="Chooser" type="button" selector="//img[@title='Open Chooser']"/> <element name="PageSize" type="input" selector="input[name='parameters[page_size]']"/> <element name="ProductAttribute" type="multiselect" selector="select[name='parameters[show_attributes][]']" /> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml index 705f2883f5839..2586ffc11d086 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml @@ -57,8 +57,29 @@ <click selector="{{WidgetSection.RuleParam}}" stepKey="clickRuleParam" /> <waitForElementVisible selector="{{WidgetSection.Chooser}}" stepKey="waitForElement" /> <click selector="{{WidgetSection.Chooser}}" stepKey="clickChooser" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskDisappear3" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskDisappear4" /> <click selector="{{WidgetSection.PreCreateCategory('$$createPreReqCategory.name$$')}}" stepKey="selectPreCategory" /> + + <!-- Test that the "<" operand functions correctly --> + <click selector="{{WidgetSection.AddParam}}" stepKey="clickAddParamBtn2" /> + <waitForElementVisible selector="{{WidgetSection.ConditionsDropdown}}" stepKey="waitForDropdownVisible2"/> + <selectOption selector="{{WidgetSection.ConditionsDropdown}}" userInput="Price" stepKey="selectPriceCondition"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskDisappear3"/> + <click selector="{{WidgetSection.RuleParamLabel('2','1')}}" stepKey="clickOperatorLabel"/> + <selectOption selector="{{WidgetSection.RuleParamSelect('2','1')}}" userInput="<" stepKey="selectLessThanCondition"/> + <click selector="{{WidgetSection.RuleParam}}" stepKey="clickRuleParam2"/> + <fillField selector="{{WidgetSection.RuleParamInput('2','2')}}" userInput="125" stepKey="fillMaxPrice"/> + + <!-- Test that the ">" operand functions correctly --> + <click selector="{{WidgetSection.AddParam}}" stepKey="clickAddParamBtn3" /> + <waitForElementVisible selector="{{WidgetSection.ConditionsDropdown}}" stepKey="waitForDropdownVisible3"/> + <selectOption selector="{{WidgetSection.ConditionsDropdown}}" userInput="Price" stepKey="selectPriceCondition2"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskDisappear5"/> + <click selector="{{WidgetSection.RuleParamLabel('3','1')}}" stepKey="clickOperatorLabel2"/> + <selectOption selector="{{WidgetSection.RuleParamSelect('3','1')}}" userInput=">" stepKey="selectLessThanCondition2"/> + <click selector="{{WidgetSection.RuleParam}}" stepKey="clickRuleParam3"/> + <fillField selector="{{WidgetSection.RuleParamInput('3','2')}}" userInput="1" stepKey="fillMinPrice"/> + <click selector="{{WidgetSection.InsertWidget}}" stepKey="clickInsertWidget" /> <waitForPageLoad stepKey="wait6" /> <scrollTo selector="{{CmsNewPagePageSeoSection.header}}" stepKey="scrollToSearchEngineTab" /> diff --git a/lib/internal/Magento/Framework/Data/Wysiwyg/Normalizer.php b/lib/internal/Magento/Framework/Data/Wysiwyg/Normalizer.php index 62e7500a302a6..bbf10e9f574cf 100644 --- a/lib/internal/Magento/Framework/Data/Wysiwyg/Normalizer.php +++ b/lib/internal/Magento/Framework/Data/Wysiwyg/Normalizer.php @@ -10,12 +10,13 @@ */ class Normalizer { - const WYSIWYG_RESERVED_CHARACTERS_REPLACEMENT_MAP = [ '{' => '^[', '}' => '^]', '"' => '`', '\\' => '|', + '<' => '^(', + '>' => '^)' ]; /** From e4f006090981154d5d404dca04f07ecbff54938a Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 8 Nov 2018 16:43:52 +0200 Subject: [PATCH 0553/1158] MAGETWO-96178: Customer addresses should be saved using Ajax --- .../Controller/Adminhtml/Address/Save.php | 2 +- .../Listing/Address/Column/Actions.php | 7 +- .../ui_component/customer_address_form.xml | 17 ++++ .../ui_component/customer_address_listing.xml | 31 ++++--- .../web/js/address/default-address.js | 36 +++---- .../web/js/form/components/insert-form.js | 55 +++++++++++ .../web/js/form/components/insert-listing.js | 53 +++++++++++ .../adminhtml/web/js/grid/columns/actions.js | 93 +++++++++++++++++++ .../view/adminhtml/web/js/grid/massactions.js | 92 ++++++++++++++++++ .../web/template/default-address.html | 7 +- .../view/base/ui_component/customer_form.xml | 33 ++++++- 11 files changed, 381 insertions(+), 45 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 855b8aedb1f73..0bdb0d44d29a9 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -163,7 +163,7 @@ public function execute(): Json 'message' => $message, 'error' => $error, 'data' => [ - 'addressId' => $addressId + 'entity_id' => $addressId ] ] ); diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index e44dc7988761f..490a14169e7b7 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -81,24 +81,26 @@ public function prepareDataSource(array $dataSource): array 'hidden' => false, ]; - $item[$name]['set_default_billing'] = [ + $item[$name]['setDefaultBilling'] = [ 'href' => $this->urlBuilder->getUrl( self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Set as default billing'), + 'isAjax' => true, 'confirm' => [ 'title' => __('Set address as default billing'), 'message' => __('Are you sure you want to set the address as default billing address?') ] ]; - $item[$name]['set_default_shipping'] = [ + $item[$name]['setDefaultShipping'] = [ 'href' => $this->urlBuilder->getUrl( self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Set as default shipping'), + 'isAjax' => true, 'confirm' => [ 'title' => __('Set address as default shipping'), 'message' => __('Are you sure you want to set the address as default shipping address?') @@ -111,6 +113,7 @@ public function prepareDataSource(array $dataSource): array ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Delete'), + 'isAjax' => true, 'confirm' => [ 'title' => __('Delete address'), 'message' => __('Are you sure you want to delete the address?') diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index a2258d7380e24..bcc5b86c5e65d 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -21,6 +21,8 @@ <button name="save" class="Magento\Customer\Block\Adminhtml\Edit\Address\SaveButton"/> </buttons> <namespace>customer_address_form</namespace> + <ajaxSave>true</ajaxSave> + <ajaxSaveType>simple</ajaxSaveType> <dataScope>data</dataScope> <deps> <dep>customer_address_form.customer_address_form_data_source</dep> @@ -44,6 +46,21 @@ </settings> </dataProvider> </dataSource> + <container name="messages" component="Magento_Ui/js/form/components/html"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="additionalClasses" xsi:type="string">message message-error</item> + <item name="visible" xsi:type="boolean">false</item> + <item name="imports" xsi:type="array"> + <item name="responseData" xsi:type="string">${ $.parentName }:responseData</item> + </item> + <item name="listens" xsi:type="array"> + <item name="responseData.error" xsi:type="string">visible</item> + <item name="responseData.messages" xsi:type="string">content</item> + </item> + </item> + </argument> + </container> <fieldset name="general"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 6c97a6da5e9e2..b48d53f9e8c5d 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -62,18 +62,23 @@ </childDefaults> </settings> </filters> - <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> - <action name="delete"> - <settings> - <confirm> - <message translate="true">Are you sure to delete selected address?</message> - <title translate="true">Delete items - - - delete - - - + + + + + + true + + Are you sure to delete selected address? + Delete items + + + delete + Delete + + + + @@ -157,7 +162,7 @@ - + entity_id diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index b4ec734cb4033..2ca75d6149da4 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -4,28 +4,18 @@ */ define([ - 'Magento_Ui/js/form/components/button' -], function (Button) { + 'Magento_Ui/js/form/components/button', + 'underscore' +], function (Button, _) { 'use strict'; return Button.extend({ defaults: { - entity_id: null, - parent_id: null - }, - - /** - * Initializes component. - * - * @returns {Button} - */ - initialize: function () { - this._super(); - if (!this.parent_id) { - this.visible(this.entity_id); + entityId: null, + parentId: null, + listens: { + entity: 'changeVisibility' } - - return this; }, /** @@ -36,16 +26,20 @@ define([ */ applyAction: function (action) { if (action.params && action.params[0]) { - action.params[0].entity_id = this.entity_id; - action.params[0].parent_id = this.parent_id; + action.params[0]['entity_id'] = this.entityId; + action.params[0]['parent_id'] = this.parentId; } else { action.params = [{ - entity_id: this.entity_id, - parent_id: this.parent_id + 'entity_id': this.entityId, + 'parent_id': this.parentId }]; } this._super(); + }, + + changeVisibility: function (entity) { + this.visible(!_.isEmpty(entity)); } }); }); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js new file mode 100644 index 0000000000000..25303899894c4 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -0,0 +1,55 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/insert-form' +], function (Insert) { + 'use strict'; + + return Insert.extend({ + defaults: { + listens: { + responseData: 'onResponse' + }, + modules: { + addressListing: '${ $.addressListingProvider }', + addressModal: '${ $.addressModalProvider }' + } + }, + + onResponse: function (responseData) { + var data; + + if (!responseData.error) { + this.addressModal().closeModal(); + this.addressListing().reload({ + refresh: true + }); + data = this.externalSource().get('data'); + this.saveAddress(responseData, data); + } + }, + + saveAddress: function (responseData, data) { + data['entity_id'] = responseData.data['entity_id']; + + if (parseFloat(data['default_billing'])) { + this.source.set('data.default_billing_address', data); + } else if ( + parseFloat(this.source.get('data.default_billing_address')['entity_id']) === data['entity_id'] + ) { + this.source.set('data.default_billing_address', []); + } + + if (parseFloat(data['default_shipping'])) { + this.source.set('data.default_shipping_address', data); + } else if ( + parseFloat(this.source.get('data.default_shipping_address')['entity_id']) === data['entity_id'] + ) { + this.source.set('data.default_shipping_address', []); + } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js new file mode 100644 index 0000000000000..0dd828b03b419 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js @@ -0,0 +1,53 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/insert-listing' +], function (Insert) { + 'use strict'; + + return Insert.extend({ + onAction: function (data) { + this[data.action + 'Action'].call(this, data.data); + }, + onMassAction: function (data) { + this[data.action + 'Massaction'].call(this, data.data); + }, + + setDefaultBillingAction: function (data) { + this.source.set('data.default_billing_address', data); + }, + + setDefaultShippingAction: function (data) { + this.source.set('data.default_shipping_address', data); + }, + + deleteAction: function (data) { + var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), + defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); + + if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { + this.source.set('data.default_shipping_address', []); + } + if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { + this.source.set('data.default_billing_address', []); + } + }, + + //TODO: release logic with massaction + deleteMassaction: function (data) { + debugger; + // var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), + // defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); + // + // if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { + // this.source.set('data.default_shipping_address', []); + // } + // if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { + // this.source.set('data.default_billing_address', []); + // } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js new file mode 100644 index 0000000000000..43ab06c8014ee --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js @@ -0,0 +1,93 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/grid/columns/actions', + 'Magento_Ui/js/modal/alert', + 'underscore', + 'jquery', + 'mage/translate' +], function (Actions, uiAlert, _, $, $t) { + 'use strict'; + + return Actions.extend({ + defaults: { + ajaxSettings: { + method: 'GET', + dataType: 'json' + }, + listens: { + action: 'onAction' + } + }, + + onAction: function (data) { + if (data.action === 'delete') { + this.source().reload({ + refresh: true + }); + } + }, + + /** + * Default action callback. Redirects to + * the specified in action's data url. + * + * @param {String} actionIndex - Action's identifier. + * @param {(Number|String)} recordId - Id of the record associated + * with a specified action. + * @param {Object} action - Action's data. + */ + defaultCallback: function (actionIndex, recordId, action) { + if (action.isAjax) { + this.request(action.href).done(function (response) { + var data; + + if (!response.error) { + data = _.findWhere(this.rows, { + _rowIndex: action.rowIndex + }); + + this.trigger('action', { + action: actionIndex, + data: data + }); + } + }.bind(this)); + + } else { + this._super(); + } + }, + + request: function (href) { + var settings = _.extend({}, this.ajaxSettings, { + url: href + }); + + $('body').trigger('processStart'); + + return $.ajax(settings) + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js new file mode 100644 index 0000000000000..1aefa2e249958 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js @@ -0,0 +1,92 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/grid/massactions', + 'Magento_Ui/js/modal/alert', + 'underscore', + 'jquery', + 'mage/translate' +], function (Massactions, uiAlert, _, $, $t) { + 'use strict'; + + return Massactions.extend({ + defaults: { + ajaxSettings: { + method: 'POST', + dataType: 'json' + }, + listens: { + massaction: 'onAction' + } + }, + + onAction: function (data) { + if (data.action === 'delete') { + this.source.reload({ + refresh: true + }); + } + }, + + defaultCallback: function (action, data) { + var itemsType, selections; + + if (action.isAjax) { + itemsType = data.excludeMode ? 'excluded' : 'selected'; + selections = {}; + + selections[itemsType] = data[itemsType]; + + if (!selections[itemsType].length) { + selections[itemsType] = false; + } + + _.extend(selections, data.params || {}); + + this.request(action.url, selections).done(function (response) { + if (!response.error) { + this.trigger('massaction', { + action: action.type, + data: selections + }); + } + }.bind(this)); + + } else { + this._super(); + } + }, + + request: function (href, data) { + var settings = _.extend({}, this.ajaxSettings, { + url: href, + data: data + }); + + $('body').trigger('processStart'); + + return $.ajax(settings) + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html index 1ee5a4da81d2b..96158e9921e22 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -4,7 +4,7 @@
    -
    +
    @@ -16,7 +16,8 @@
    - + +
    @@ -36,7 +37,7 @@
    VAT:
    - +
    diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 17d4e7aab5cd3..d6d61c892e00d 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -319,6 +319,9 @@ Default Billing Address customer-default-billing-address-content The customer does not have default billing address + + true + @@ -353,7 +356,8 @@ Edit true - ${ $.provider}:data.default_billing_address.entity_id + ${ $.provider}:data.default_billing_address.entity_id + ${ $.provider}:data.default_billing_address @@ -365,6 +369,9 @@ Default Shipping Address customer-default-shipping-address-content The customer does not have default shipping address + + true + @@ -399,7 +406,8 @@ Edit true - ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address @@ -427,7 +435,7 @@ Add New Address - ${ $.provider}:data.customer_id + ${ $.provider}:data.customer_id @@ -437,8 +445,15 @@ - + + + + ns = customer_address_listing, index = customer_address_listing + ${ $.parentName } + + + ajax customer_address_edit 1 @@ -447,10 +462,16 @@ ${ $.parentName } ${ $.ns }.customer_address_form_data_source customer_address_form + + ${ $.externalProvider }:data.parent_id + + + ${ $.provider}:data.customer_id + - + false @@ -466,6 +487,8 @@ ${ $.provider }:data.customer.entity_id + ns = ${ $.ns }, index = actions:action + ns = ${ $.ns }, index = listing_massaction:massaction From e5e7db172a906ae3baf94379d673db4856a78643 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina Date: Thu, 8 Nov 2018 17:48:37 +0300 Subject: [PATCH 0554/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../view/adminhtml/web/js/grouped-product-grid.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 58c3b79022a62..28553eaa41d12 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -128,7 +128,7 @@ define([ * Event handler for "Send to bottom" button * * @param {Object} positionObj - * @return {boolean} + * @return {Boolean} */ sendToBottom: function (positionObj) { @@ -152,7 +152,7 @@ define([ * Event handler for "Send to top" button * * @param {Object} positionObj - * @returns {boolean} + * @return {Boolean} */ sendToTop: function (positionObj) { var objectToUpdate = this.getObjectToUpdate(positionObj), @@ -189,7 +189,7 @@ define([ * Value function for position input * * @param {Object} data - * @return {number} + * @return {Number} */ getCalculatedPosition: function (data) { return (~~this.currentPage() - 1) * this.pageSize + this.elems().pluck("name").indexOf(data.name); @@ -198,7 +198,7 @@ define([ /** * Return Page Boundary * - * @return {number} + * @return {Number} */ getDefaultPageBoundary: function () { return ~~this.currentPage() * this.pageSize - 1; @@ -207,7 +207,7 @@ define([ /** * Returns position for last element to be moved after * - * @return {number} + * @return {Number} */ getGlobalMaxPosition: function () { return _.max(this.recordData().map(function (r) { From 803cdb1a15c3f6736c3674a8eb24aa8713992e63 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 09:23:21 -0600 Subject: [PATCH 0555/1158] ENGCOM-3408: #18956 Fixes for set root_category_id #18958 - fixed docblocks --- .../Model/Config/Importer/Processor/Create.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php index 71ffa5303293d..1fb9f1c224d3e 100644 --- a/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php +++ b/app/code/Magento/Store/Model/Config/Importer/Processor/Create.php @@ -17,8 +17,6 @@ /** * The processor for creating of new entities. - * - * {@inheritdoc} */ class Create implements ProcessorInterface { @@ -85,7 +83,9 @@ public function __construct( /** * Creates entities in application according to the data set. * - * {@inheritdoc} + * @param array $data The data to be processed + * @return void + * @throws RuntimeException If processor was unable to finish execution */ public function run(array $data) { @@ -230,8 +230,7 @@ private function createStores(array $items, array $data) } /** - * Searches through given websites and compares with current websites. - * Returns found website. + * Searches through given websites and compares with current websites and returns found website. * * @param array $data The data to be searched in * @param string $websiteId The website id @@ -253,8 +252,7 @@ private function detectWebsiteById(array $data, $websiteId) } /** - * Searches through given groups and compares with current websites. - * Returns found group. + * Searches through given groups and compares with current websites and returns found group. * * @param array $data The data to be searched in * @param string $groupId The group id @@ -276,8 +274,7 @@ private function detectGroupById(array $data, $groupId) } /** - * Searches through given stores and compares with current stores. - * Returns found store. + * Searches through given stores and compares with current stores and returns found store. * * @param array $data The data to be searched in * @param string $storeId The store id From 9f9f5189286db7439973b52f15354e74363b4284 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina Date: Thu, 8 Nov 2018 18:30:07 +0300 Subject: [PATCH 0556/1158] MAGETWO-91639: Tax is added despite customer group changes - Update automated test --- .../AdminDeleteCustomerGroupActionGroup.xml | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml index fd5cf8d43d8fb..b62a647ebdf62 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -7,26 +7,20 @@ --> + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - - - - - - - - - - - - - - - - + + + + + + + + + + From fad135663cc088694ef492a0d676c9a85e30450b Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Thu, 8 Nov 2018 09:47:07 -0600 Subject: [PATCH 0557/1158] MAGETWO-95770: Saved multi line attribute data displayed incorrectly on customer edit address page - Adjusted test --- .../Customer/Test/Unit/Model/Customer/DataProviderTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php index 50c21379054bf..d13c173cb12c2 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php @@ -649,10 +649,8 @@ public function testGetData() 2 => [ 'firstname' => 'firstname', 'lastname' => 'lastname', - 'street' => [ - 'street', - 'street', - ], + // Won't be an array because it isn't defined as a multiline field in this test + 'street' => "street\nstreet", 'default_billing' => 2, 'default_shipping' => 2, ] From a6aa2394b1674c428cf5c466dd92133aea1722c0 Mon Sep 17 00:00:00 2001 From: Mariana Lashch Date: Thu, 8 Nov 2018 18:20:49 +0200 Subject: [PATCH 0558/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - add action --- .../Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml index 889db82db644d..357f496b1cba0 100644 --- a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml @@ -135,6 +135,7 @@ + From f70f7f772f7ad16f115e989812a7462d0d8a2f39 Mon Sep 17 00:00:00 2001 From: Mariana Lashch Date: Thu, 8 Nov 2018 18:56:16 +0200 Subject: [PATCH 0559/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - add element and action on it --- .../Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml | 1 + .../Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml index 357f496b1cba0..3009fa1fc8a25 100644 --- a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml @@ -136,6 +136,7 @@ + diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index e0a3092c13321..681b3a37f506c 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -12,6 +12,7 @@ + From 1862d2c02744a33a5b8b1a44eab53adf1bb79048 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 11:53:19 -0600 Subject: [PATCH 0560/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed docblock --- .../Framework/Interception/AbstractPlugin.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php index 60eb511dcb6b5..2a34f18fb0a0d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php @@ -7,25 +7,35 @@ /** * Class GeneralTest + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ abstract class AbstractPlugin extends \PHPUnit\Framework\TestCase { /** + * Config reader + * * @var \PHPUnit_Framework_MockObject_MockObject */ protected $_configReader; /** + * Object Manager + * * @var \Magento\Framework\ObjectManagerInterface */ protected $_objectManager; /** + * Applicartion Object Manager + * * @var \Magento\Framework\ObjectManagerInterface */ private $applicationObjectManager; + /** + * Set up + */ public function setUp() { if (!$this->_objectManager) { @@ -36,11 +46,17 @@ public function setUp() \Magento\Framework\App\ObjectManager::setInstance($this->_objectManager); } + /** + * Tear down + */ public function tearDown() { \Magento\Framework\App\ObjectManager::setInstance($this->applicationObjectManager); } + /** + * Set up Interception Config + */ public function setUpInterceptionConfig($pluginConfig) { $config = new \Magento\Framework\Interception\ObjectManager\Config\Developer(); From 2f5b730fa800c528e8f38da91154089f094090dc Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 11:54:35 -0600 Subject: [PATCH 0561/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed static test --- .../Framework/Interception/Config/CacheManagerTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php index 9d5abd1a8a6c6..6b0487d4afdae 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php @@ -40,7 +40,8 @@ protected function setUp() $this->serializer = $this->objectManager->get(\Magento\Framework\Serialize\SerializerInterface::class); $this->cache = $this->objectManager->get(\Magento\Framework\App\CacheInterface::class); - $this->configWriter = $this->objectManager->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); + $this->configWriter = + $this->objectManager->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); $this->initializeMetadataDirectory(); } @@ -125,7 +126,9 @@ private function getConfig() \Magento\Framework\Interception\Config\CacheManager::class, [ 'cacheId' => self::CACHE_ID, - 'compiledLoader' => $this->objectManager->create(\Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class), + 'compiledLoader' => $this->objectManager->create( + \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::class + ), ] ); } From 9135654c9f123ca8a22f0aa23677fa8222912e9a Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 11:55:42 -0600 Subject: [PATCH 0562/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed docblock --- .../Magento/Framework/Interception/Config/CacheManager.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Interception/Config/CacheManager.php b/lib/internal/Magento/Framework/Interception/Config/CacheManager.php index cd16e2277d87a..a754215bbe743 100644 --- a/lib/internal/Magento/Framework/Interception/Config/CacheManager.php +++ b/lib/internal/Magento/Framework/Interception/Config/CacheManager.php @@ -9,8 +9,9 @@ namespace Magento\Framework\Interception\Config; /** - * Interception cache manager responsible for handling interaction with compiled and - * uncompiled interception data + * Interception cache manager. + * + * Responsible for handling interaction with compiled and uncompiled interception data */ class CacheManager { From 5db83d30c9ca29a0f6613932196c9b0f3bc89de8 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 11:58:27 -0600 Subject: [PATCH 0563/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 Fixed dockblock --- .../Framework/Interception/Config/Config.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/internal/Magento/Framework/Interception/Config/Config.php b/lib/internal/Magento/Framework/Interception/Config/Config.php index 4eeed4788a05e..7632970705fff 100644 --- a/lib/internal/Magento/Framework/Interception/Config/Config.php +++ b/lib/internal/Magento/Framework/Interception/Config/Config.php @@ -1,7 +1,5 @@ _cacheId = $cacheId; $this->_reader = $reader; $this->_scopeList = $scopeList; - $this->cacheManager = $cacheManager ?? \Magento\Framework\App\ObjectManager::getInstance()->get(CacheManager::class); + $this->cacheManager = + $cacheManager ?? \Magento\Framework\App\ObjectManager::getInstance()->get(CacheManager::class); $intercepted = $this->cacheManager->load($cacheId); if ($intercepted !== null) { $this->_intercepted = $intercepted; @@ -166,7 +170,7 @@ protected function _inheritInterception($type) } /** - * {@inheritdoc} + * @inheritdoc */ public function hasPlugins($type) { @@ -193,7 +197,7 @@ private function initializeUncompiled($classDefinitions = []) /** * Generate intercepted array to store in compiled metadata or frontend cache * - * @param $classDefinitions + * @param array $classDefinitions */ private function generateIntercepted($classDefinitions) { From 40c58fc482c87a0840e2b1d05c3f951c30f140f2 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 11:59:34 -0600 Subject: [PATCH 0564/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed docblock --- setup/src/Magento/Setup/Console/Command/DiCompileCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php index ee26e71d94f30..014d699cb239d 100644 --- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php @@ -103,7 +103,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ protected function configure() { @@ -132,7 +132,7 @@ private function checkEnvironment() } /** - * {@inheritdoc} + * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { From be71e3b26e103dbecffa1f9397b20f7e794e36f3 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 12:01:00 -0600 Subject: [PATCH 0565/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed docblock --- .../src/Magento/Setup/Module/Di/App/Task/Operation/Area.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php index 7acc84e356c4d..edc2a485278a6 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php @@ -10,6 +10,9 @@ use Magento\Setup\Module\Di\Compiler\Config; use Magento\Setup\Module\Di\Definition\Collection as DefinitionsCollection; +/** + * Area configuration aggregation + */ class Area implements OperationInterface { /** @@ -67,7 +70,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function doOperation() { From b80d92d59882c4f686aa8e538ad167ef4630be43 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 12:02:10 -0600 Subject: [PATCH 0566/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed docblock --- .../Setup/Module/Di/Compiler/Config/Writer/Filesystem.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php index ee9321c5d4199..953dc04f4cd32 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php @@ -11,6 +11,8 @@ use Magento\Setup\Module\Di\Compiler\Config\WriterInterface; /** + * Class for writing DI Compiler Configuration + * * @deprecated Moved to Framework to allow broader reuse * @see \Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem */ From 33435b7c4ac6ca2fdbaf07a393ba8d96f97de068 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 8 Nov 2018 12:02:45 -0600 Subject: [PATCH 0567/1158] ENGCOM-3243: Write intercepted mapping to generated/metadata during compilation #18648 - Fixed static test --- .../Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php index 03b423bb32b0f..fbdbc951462e4 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php @@ -48,7 +48,8 @@ protected function setUp() $this->configReaderMock = $this->getMockBuilder(\Magento\Setup\Module\Di\Compiler\Config\Reader::class) ->disableOriginalConstructor() ->getMock(); - $this->configWriterMock = $this->getMockBuilder(\Magento\Framework\App\ObjectManager\ConfigWriterInterface::class) + $this->configWriterMock = + $this->getMockBuilder(\Magento\Framework\App\ObjectManager\ConfigWriterInterface::class) ->disableOriginalConstructor() ->getMock(); $this->configChain = $this->getMockBuilder(\Magento\Setup\Module\Di\Compiler\Config\ModificationChain::class) From 12d035d335e3d8903253cf00f155c35efb701df5 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Thu, 8 Nov 2018 13:29:50 -0600 Subject: [PATCH 0568/1158] MAGETWO-96192: Products with "Less Than", "Greater Than", "Less Than Or Equal", "Greater Than Or Equal" condition returns error on storefront - Updatd integration test --- .../Magento/Widget/Setup/LayoutUpdateConverterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php b/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php index 43c0bd202cc92..3d43fb5a44575 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php @@ -34,7 +34,7 @@ public function convertDataProvider() // @codingStandardsIgnoreStart $beginning = 'show_pager0products_count10'; $serializedWidgetXml = 'conditions_encodeda:3:[i:1;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Combine`;s:10:`aggregator`;s:3:`all`;s:5:`value`;s:1:`1`;s:9:`new_child`;s:0:``;]s:4:`1--1`;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`;s:9:`attribute`;s:3:`sku`;s:8:`operator`;s:2:`()`;s:5:`value`;s:15:`simple, simple1`;]s:4:`1--2`;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`;s:9:`attribute`;s:5:`price`;s:8:`operator`;s:2:`<=`;s:5:`value`;s:2:`10`;]]'; - $jsonEncodedWidgetXml = 'conditions_encoded^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,`aggregator`:`all`,`value`:`1`,`new_child`:``^],`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`sku`,`operator`:`()`,`value`:`simple, simple1`^],`1--2`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`price`,`operator`:`<=`,`value`:`10`^]^]'; + $jsonEncodedWidgetXml = 'conditions_encoded^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,`aggregator`:`all`,`value`:`1`,`new_child`:``^],`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`sku`,`operator`:`()`,`value`:`simple, simple1`^],`1--2`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`price`,`operator`:`^(=`,`value`:`10`^]^]'; $ending = 'page_var_namepobqks'; // @codingStandardsIgnoreEnd return [ From 336f62c887b625cdec1a050a42aa19538eb51005 Mon Sep 17 00:00:00 2001 From: Deepty Thampy Date: Thu, 8 Nov 2018 19:07:56 -0600 Subject: [PATCH 0569/1158] MAGETWO-89232: Validation error appears if duplicate product twice - added functional test to cover the bug fix --- .../AdminProductGridActionGroup.xml | 7 ++++ .../Section/AdminProductFormActionSection.xml | 1 + .../AdminCreateProductDuplicateUrlkeyTest.xml | 42 +++++++++++++++++++ .../AdminSaveAndCloseActionGroup.xml | 6 +++ 4 files changed, 56 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml index 1bd9bb4a09c86..a077eced6d5d5 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml @@ -164,6 +164,13 @@ + + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml index afbaba41a9bb7..c7d4cd16d788a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml @@ -15,5 +15,6 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml index 95d74b9653113..8dffc3d352a7b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml @@ -40,4 +40,46 @@ + + + + + + <description value="No validation errors when trying to duplicate product twice"/> + <severity value="MAJOR"/> + <testCaseId value="MC-5472"/> + <group value="product"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <!--Delete all products by filtering grid and using mass delete action--> + <actionGroup ref="deleteAllDuplicateProductUsingProductGrid" stepKey="deleteAllDuplicateProducts"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <deleteData createDataKey="createCategory" stepKey="deletePreReqCatalog" /> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct1"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct1"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <!--Save and duplicated the product once--> + <actionGroup ref="AdminFormSaveAndDuplicate" stepKey="saveAndDuplicateProductForm1"/> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct2"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct2"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <!--Save and duplicated the product second time--> + <actionGroup ref="AdminFormSaveAndDuplicate" stepKey="saveAndDuplicateProductForm2"/> + </test> </tests> diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminSaveAndCloseActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminSaveAndCloseActionGroup.xml index 9a9458ab34d2b..20c8927d49171 100644 --- a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminSaveAndCloseActionGroup.xml +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminSaveAndCloseActionGroup.xml @@ -13,4 +13,10 @@ <click selector="{{AdminProductFormActionSection.saveAndClose}}" stepKey="clickOnSaveAndClose"/> <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="assertSaveMessageSuccess"/> </actionGroup> + <actionGroup name="AdminFormSaveAndDuplicate"> + <click selector="{{AdminProductFormActionSection.saveArrow}}" stepKey="openSaveDropDown"/> + <click selector="{{AdminProductFormActionSection.saveAndDuplicate}}" stepKey="clickOnSaveAndDuplicate"/> + <see selector="{{AdminProductMessagesSection.successMessage}}" stepKey="assertSaveSuccess" userInput="You saved the product."/> + <see selector="{{AdminProductMessagesSection.successMessage}}" stepKey="assertDuplicateSuccess" userInput="You duplicated the product."/> + </actionGroup> </actionGroups> From dc51f3e13799a46d8ea6204892c230d15e142b84 Mon Sep 17 00:00:00 2001 From: Alexandr Voronoy <servermed@gmail.com> Date: Fri, 9 Nov 2018 04:25:16 +0200 Subject: [PATCH 0570/1158] Missed PHPDoc argument headers in method --- .../framework/Magento/TestFramework/TestCase/GraphQlAbstract.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php index cfcd5dd1b51dd..9754a340900e2 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php @@ -33,6 +33,7 @@ abstract class GraphQlAbstract extends WebapiAbstract * @param string $query * @param array $variables * @param string $operationName + * @param array $headers * @return array|int|string|float|bool GraphQL call results * @throws \Exception */ From 97da50434f0577ae602dfd79493323793f91baee Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Fri, 9 Nov 2018 10:42:59 +0200 Subject: [PATCH 0571/1158] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add custom DataProvider for customer addresses listing; --- .../Listing/Address/DataProvider.php | 52 +++++++++++++++++++ .../ui_component/customer_address_listing.xml | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php new file mode 100644 index 0000000000000..df92e7c1c9421 --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Ui\Component\Listing\Address; + +use Magento\Customer\Model\ResourceModel\Address\Grid\CollectionFactory; + +/** + * Custom DataProvider for customer addresses listing + */ +class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider +{ + /** + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName + * @param CollectionFactory $collectionFactory + * @param array $meta + * @param array $data + */ + public function __construct( + $name, + $primaryFieldName, + $requestFieldName, + CollectionFactory $collectionFactory, + array $meta = [], + array $data = [] + ) { + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->collection = $collectionFactory->create(); + } + + /** + * Add country key for default billing/shipping blocks on customer addresses tab + * + * @return array + */ + public function getData(): array + { + $collection = $this->getCollection(); + $data = $collection->toArray(); + foreach ($data['items'] as $key => $item) { + if (isset($item['country_id']) && !isset($item['country'])) { + $data['items'][$key]['country'] = $item['country_id']; + } + } + + return $data; + } +} diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 6c97a6da5e9e2..7fb8c49749f2d 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -28,7 +28,7 @@ <updateUrl path="mui/index/render"/> </settings> <aclResource>Magento_Customer::manage</aclResource> - <dataProvider class="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider" name="customer_address_listing_data_source"> + <dataProvider class="Magento\Customer\Ui\Component\Listing\Address\DataProvider" name="customer_address_listing_data_source"> <settings> <requestFieldName>id</requestFieldName> <primaryFieldName>entity_id</primaryFieldName> From 15668ac2018ebfae033bd0cc18ded3e8628549ec Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Fri, 9 Nov 2018 12:30:37 +0300 Subject: [PATCH 0572/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 28553eaa41d12..1ec11797e311f 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -170,6 +170,7 @@ define([ }); this.reloadGridData(recordData); } + return false; }, From 10e64f25fc69c35010a74cb5628e67a64e6f9256 Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Fri, 9 Nov 2018 12:16:37 +0200 Subject: [PATCH 0573/1158] Add save product with image integration test scenario --- .../Catalog/Model/ProductRepositoryTest.php | 48 +++++++++++++++++++ .../_files/product_simple_with_image.php | 45 +++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_image.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php index 39752460a1cd7..d4016b2bfa8d4 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php @@ -90,4 +90,52 @@ public function skuDataProvider(): array ['sku' => 'simple '], ]; } + + /** + * Test save product with gallery image + * + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_image.php + * + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\StateException + */ + public function testSaveProductWithGalleryImage(): void + { + /** @var $mediaConfig \Magento\Catalog\Model\Product\Media\Config */ + $mediaConfig = Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Model\Product\Media\Config::class); + + /** @var $mediaDirectory \Magento\Framework\Filesystem\Directory\WriteInterface */ + $mediaDirectory = Bootstrap::getObjectManager() + ->get(\Magento\Framework\Filesystem::class) + ->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + + $product = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $product->load(1); + + $path = $mediaConfig->getBaseMediaPath() . '/magento_image.jpg'; + $absolutePath = $mediaDirectory->getAbsolutePath() . $path; + $product->addImageToMediaGallery($absolutePath, [ + 'image', + 'small_image', + ], false, false); + + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $productRepository->save($product); + + $gallery = $product->getData('media_gallery'); + $this->assertArrayHasKey('images', $gallery); + $images = array_values($gallery['images']); + + $this->assertNotEmpty($gallery); + $this->assertTrue(isset($images[0]['file'])); + $this->assertStringStartsWith('/m/a/magento_image', $images[0]['file']); + $this->assertArrayHasKey('media_type', $images[0]); + $this->assertEquals('image', $images[0]['media_type']); + $this->assertStringStartsWith('/m/a/magento_image', $product->getData('image')); + $this->assertStringStartsWith('/m/a/magento_image', $product->getData('small_image')); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_image.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_image.php new file mode 100644 index 0000000000000..252f99c97b787 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_image.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Catalog\Api\Data\ProductExtensionInterfaceFactory; +use Magento\Framework\App\Filesystem\DirectoryList; + +\Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize(); + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(1) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED); + +/** @var $mediaConfig \Magento\Catalog\Model\Product\Media\Config */ +$mediaConfig = $objectManager->get(\Magento\Catalog\Model\Product\Media\Config::class); + +/** @var $mediaDirectory \Magento\Framework\Filesystem\Directory\WriteInterface */ +$mediaDirectory = $objectManager->get(\Magento\Framework\Filesystem::class) + ->getDirectoryWrite(DirectoryList::MEDIA); + +$targetDirPath = $mediaConfig->getBaseMediaPath(); +$targetTmpDirPath = $mediaConfig->getBaseTmpMediaPath(); + +$mediaDirectory->create($targetDirPath); +$mediaDirectory->create($targetTmpDirPath); + +$dist = $mediaDirectory->getAbsolutePath($mediaConfig->getBaseMediaPath() . DIRECTORY_SEPARATOR . 'magento_image.jpg'); +copy(__DIR__ . '/magento_image.jpg', $dist); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$productRepository->save($product); From 88b3e279455ffbcb5e901ab747dbd052bb851465 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Fri, 9 Nov 2018 13:33:57 +0300 Subject: [PATCH 0574/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Fix static tests --- .../view/adminhtml/web/js/grouped-product-grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js index 1ec11797e311f..0ac3b58d6e3a7 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js +++ b/app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product-grid.js @@ -193,7 +193,7 @@ define([ * @return {Number} */ getCalculatedPosition: function (data) { - return (~~this.currentPage() - 1) * this.pageSize + this.elems().pluck("name").indexOf(data.name); + return (~~this.currentPage() - 1) * this.pageSize + this.elems().pluck('name').indexOf(data.name); }, /** From 2307e16105e031c0826d218cf81ffe7949191a0b Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov <isentiabov@magento.com> Date: Fri, 9 Nov 2018 09:17:57 +0200 Subject: [PATCH 0575/1158] MAGETWO-96218: [2.3] Track not saved during shipment creation through API - Refactored `getTracks` method - Fixed relation processor - Updated unit and integration tests --- .../Magento/Sales/Model/Order/Shipment.php | 38 +++-- .../ResourceModel/Order/Shipment/Relation.php | 4 +- .../Order/Shipment/RelationTest.php | 146 ++++++++---------- .../Sales/Model/Order/ShipmentTest.php | 7 +- 4 files changed, 93 insertions(+), 102 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php index ebedc869e14bd..cecee4283648d 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment.php +++ b/app/code/Magento/Sales/Model/Order/Shipment.php @@ -354,7 +354,15 @@ public function addItem(\Magento\Sales\Model\Order\Shipment\Item $item) public function getTracksCollection() { if ($this->tracksCollection === null) { - $this->tracksCollection = $this->_trackCollectionFactory->create()->setShipmentFilter($this->getId()); + $this->tracksCollection = $this->_trackCollectionFactory->create(); + + if ($this->getId()) { + $this->tracksCollection->setShipmentFilter($this->getId()); + + foreach ($this->tracksCollection as $item) { + $item->setShipment($this); + } + } } return $this->tracksCollection; @@ -400,19 +408,20 @@ public function getTrackById($trackId) */ public function addTrack(\Magento\Sales\Model\Order\Shipment\Track $track) { - $track->setShipment( - $this - )->setParentId( - $this->getId() - )->setOrderId( - $this->getOrderId() - )->setStoreId( - $this->getStoreId() - ); + $track->setShipment($this) + ->setParentId($this->getId()) + ->setOrderId($this->getOrderId()) + ->setStoreId($this->getStoreId()); + if (!$track->getId()) { $this->getTracksCollection()->addItem($track); } + $tracks = $this->getTracks(); + // as it's a new track entity, the collection doesn't contain it + $tracks[] = $track; + $this->setTracks($tracks); + /** * Track saving is implemented in _afterSave() * This enforces \Magento\Framework\Model\AbstractModel::save() not to skip _afterSave() @@ -582,14 +591,15 @@ public function setItems($items) /** * Returns tracks * - * @return \Magento\Sales\Api\Data\ShipmentTrackInterface[] + * @return \Magento\Sales\Api\Data\ShipmentTrackInterface[]|null */ public function getTracks() { + if (!$this->getId()) { + return $this->getData(ShipmentInterface::TRACKS); + } + if ($this->getData(ShipmentInterface::TRACKS) === null) { - foreach ($this->getTracksCollection() as $item) { - $item->setShipment($this); - } $this->setData(ShipmentInterface::TRACKS, $this->getTracksCollection()->getItems()); } return $this->getData(ShipmentInterface::TRACKS); diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php index 9c8671d02c578..5851b2d936139 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php @@ -62,8 +62,8 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) $this->shipmentItemResource->save($item); } } - if (null !== $object->getTracksCollection()) { - foreach ($object->getTracksCollection() as $track) { + if (null !== $object->getTracks()) { + foreach ($object->getTracks() as $track) { $track->setParentId($object->getId()); $this->shipmentTrackResource->save($track); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php b/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php index a7a615fb0f508..530306d77d3ed 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php @@ -3,145 +3,125 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Sales\Test\Unit\Model\ResourceModel\Order\Shipment; +use Magento\Sales\Model\Order\Shipment; +use Magento\Sales\Model\Order\Shipment\Comment as CommentEntity; +use Magento\Sales\Model\Order\Shipment\Item as ItemEntity; +use Magento\Sales\Model\Order\Shipment\Track as TrackEntity; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Comment; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Item; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Relation; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Track; +use PHPUnit\Framework\MockObject\MockObject; + /** * Class RelationTest */ class RelationTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Relation + * @var Relation */ - protected $relationProcessor; + private $relationProcessor; /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Item|\PHPUnit_Framework_MockObject_MockObject + * @var Item|MockObject */ - protected $itemResourceMock; + private $itemResource; /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Track|\PHPUnit_Framework_MockObject_MockObject + * @var Track|MockObject */ - protected $trackResourceMock; + private $trackResource; /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Comment|\PHPUnit_Framework_MockObject_MockObject + * @var Comment|MockObject */ - protected $commentResourceMock; + private $commentResource; /** - * @var \Magento\Sales\Model\Order\Shipment\Comment|\PHPUnit_Framework_MockObject_MockObject + * @var CommentEntity|MockObject */ - protected $commentMock; + private $comment; /** - * @var \Magento\Sales\Model\Order\Shipment\Track|\PHPUnit_Framework_MockObject_MockObject + * @var TrackEntity|MockObject */ - protected $trackMock; + private $track; /** - * @var \Magento\Sales\Model\Order\Shipment|\PHPUnit_Framework_MockObject_MockObject + * @var Shipment|MockObject */ - protected $shipmentMock; + private $shipment; /** - * @var \Magento\Sales\Model\Order\Shipment\Item|\PHPUnit_Framework_MockObject_MockObject + * @var ItemEntity|MockObject */ - protected $itemMock; + private $item; - protected function setUp() + /** + * @inheritdoc + */ + protected function setUp(): void { - $this->itemResourceMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment\Item::class) + $this->itemResource = $this->getMockBuilder(Item::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'save' - ] - ) ->getMock(); - $this->commentResourceMock = $this->getMockBuilder( - \Magento\Sales\Model\ResourceModel\Order\Shipment\Comment::class - ) + $this->commentResource = $this->getMockBuilder(Comment::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'save' - ] - ) ->getMock(); - $this->trackResourceMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment\Track::class) + $this->trackResource = $this->getMockBuilder(Track::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'save' - ] - ) ->getMock(); - $this->shipmentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + $this->shipment = $this->getMockBuilder(Shipment::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'getId', - 'getItems', - 'getTracks', - 'getComments', - 'getTracksCollection', - ] - ) ->getMock(); - $this->itemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) + $this->item = $this->getMockBuilder(ItemEntity::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'setParentId' - ] - ) ->getMock(); - $this->trackMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + $this->track = $this->getMockBuilder(TrackEntity::class) ->disableOriginalConstructor() ->getMock(); - $this->commentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + $this->comment = $this->getMockBuilder(Shipment::class) ->disableOriginalConstructor() ->getMock(); - $this->relationProcessor = new \Magento\Sales\Model\ResourceModel\Order\Shipment\Relation( - $this->itemResourceMock, - $this->trackResourceMock, - $this->commentResourceMock + $this->relationProcessor = new Relation( + $this->itemResource, + $this->trackResource, + $this->commentResource ); } - public function testProcessRelations() + /** + * Checks saving shipment relations. + * + * @throws \Exception + */ + public function testProcessRelations(): void { - $this->shipmentMock->expects($this->exactly(3)) - ->method('getId') + $this->shipment->method('getId') ->willReturn('shipment-id-value'); - $this->shipmentMock->expects($this->exactly(2)) - ->method('getItems') - ->willReturn([$this->itemMock]); - $this->shipmentMock->expects($this->exactly(2)) - ->method('getComments') - ->willReturn([$this->commentMock]); - $this->shipmentMock->expects($this->exactly(2)) - ->method('getTracksCollection') - ->willReturn([$this->trackMock]); - $this->itemMock->expects($this->once()) - ->method('setParentId') + $this->shipment->method('getItems') + ->willReturn([$this->item]); + $this->shipment->method('getComments') + ->willReturn([$this->comment]); + $this->shipment->method('getTracks') + ->willReturn([$this->track]); + $this->item->method('setParentId') ->with('shipment-id-value') ->willReturnSelf(); - $this->itemResourceMock->expects($this->once()) - ->method('save') - ->with($this->itemMock) + $this->itemResource->method('save') + ->with($this->item) ->willReturnSelf(); - $this->commentResourceMock->expects($this->once()) - ->method('save') - ->with($this->commentMock) + $this->commentResource->method('save') + ->with($this->comment) ->willReturnSelf(); - $this->trackResourceMock->expects($this->once()) - ->method('save') - ->with($this->trackMock) + $this->trackResource->method('save') + ->with($this->track) ->willReturnSelf(); - $this->relationProcessor->processRelation($this->shipmentMock); + $this->relationProcessor->processRelation($this->shipment); } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php index 0679fc6ffe6cb..1d04a79ae3f84 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php @@ -90,10 +90,11 @@ public function testAddTrack() $items[$item->getId()] = $item->getQtyOrdered(); } /** @var \Magento\Sales\Model\Order\Shipment $shipment */ - $shipment = $this->objectManager->get(ShipmentFactory::class)->create($order, $items); + $shipment = $this->objectManager->get(ShipmentFactory::class) + ->create($order, $items); $shipment->addTrack($track); - $shipment->save(); - $saved = $this->shipmentRepository->save($shipment); + $this->shipmentRepository->save($shipment); + $saved = $this->shipmentRepository->get((int)$shipment->getEntityId()); self::assertNotEmpty($saved->getTracks()); } From fe7b9ac55097b64a023e607acacb1857f1926367 Mon Sep 17 00:00:00 2001 From: Vasilii Burlacu <v.burlacu@atwix.com> Date: Fri, 9 Nov 2018 13:48:17 +0200 Subject: [PATCH 0576/1158] magento/magento2:#19101 - API REST and Reserved Order Id - Fixed issue "Can not update cart with a reserved order number like 000000651" --- app/code/Magento/Quote/Api/Data/CartInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Quote/Api/Data/CartInterface.php b/app/code/Magento/Quote/Api/Data/CartInterface.php index 551833e3effb1..b87869de6b3df 100644 --- a/app/code/Magento/Quote/Api/Data/CartInterface.php +++ b/app/code/Magento/Quote/Api/Data/CartInterface.php @@ -223,14 +223,14 @@ public function setBillingAddress(\Magento\Quote\Api\Data\AddressInterface $bill /** * Returns the reserved order ID for the cart. * - * @return int|null Reserved order ID. Otherwise, null. + * @return string|null Reserved order ID. Otherwise, null. */ public function getReservedOrderId(); /** * Sets the reserved order ID for the cart. * - * @param int $reservedOrderId + * @param string $reservedOrderId * @return $this */ public function setReservedOrderId($reservedOrderId); From de8d0a9938ff771a09bb9be6bbf93430e462243c Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Fri, 9 Nov 2018 13:50:49 +0200 Subject: [PATCH 0577/1158] MAGETWO-91513: Password reset email cannot be sent if the customer does not have customer attribute set that is changed to required after original account creation - Skipping address validation for reset password flow --- .../Customer/Model/AccountManagement.php | 12 ++++ .../Customer/Model/ResourceModel/Customer.php | 4 +- .../Model/ResourceModel/Customer/Relation.php | 62 ++++++++++--------- .../ResourceModel/CustomerRepository.php | 17 ++++- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 9173307a7d270..553cfd2e37a06 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -1384,6 +1384,7 @@ public function changeResetPasswordLinkToken($customer, $passwordLinkToken) $customerSecure->setRpTokenCreatedAt( $this->dateTimeFactory->create()->format(DateTime::DATETIME_PHP_FORMAT) ); + $this->setIgnoreValidationFlag($customer); $this->customerRepository->save($customer); } return true; @@ -1537,4 +1538,15 @@ private function destroyCustomerSessions($customerId) $this->saveHandler->destroy($sessionId); } } + + /** + * Set ignore_validation_flag for reset password flow to skip unnecessary address and customer validation + * + * @param Customer $customer + * @return void + */ + private function setIgnoreValidationFlag($customer) + { + $customer->setData('ignore_validation_flag', true); + } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Customer.php b/app/code/Magento/Customer/Model/ResourceModel/Customer.php index f510201559687..2eb1ef897e70e 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Customer.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Customer.php @@ -151,7 +151,9 @@ protected function _beforeSave(\Magento\Framework\DataObject $customer) $customer->setConfirmation(null); } - $this->_validate($customer); + if (!$customer->getData('ignore_validation_flag')) { + $this->_validate($customer); + } return $this; } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Customer/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Customer/Relation.php index e55c5d443c9d1..96f47154e874e 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Customer/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Customer/Relation.php @@ -23,41 +23,43 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $customer $defaultBillingId = $customer->getData('default_billing'); $defaultShippingId = $customer->getData('default_shipping'); - /** @var \Magento\Customer\Model\Address $address */ - foreach ($customer->getAddresses() as $address) { - if ($address->getData('_deleted')) { - if ($address->getId() == $defaultBillingId) { - $customer->setData('default_billing', null); - } + if (!$customer->getData('ignore_validation_flag')) { + /** @var \Magento\Customer\Model\Address $address */ + foreach ($customer->getAddresses() as $address) { + if ($address->getData('_deleted')) { + if ($address->getId() == $defaultBillingId) { + $customer->setData('default_billing', null); + } - if ($address->getId() == $defaultShippingId) { - $customer->setData('default_shipping', null); - } + if ($address->getId() == $defaultShippingId) { + $customer->setData('default_shipping', null); + } - $removedAddressId = $address->getId(); - $address->delete(); + $removedAddressId = $address->getId(); + $address->delete(); - // Remove deleted address from customer address collection - $customer->getAddressesCollection()->removeItemByKey($removedAddressId); - } else { - $address->setParentId( - $customer->getId() - )->setStoreId( - $customer->getStoreId() - )->setIsCustomerSaveTransaction( - true - )->save(); + // Remove deleted address from customer address collection + $customer->getAddressesCollection()->removeItemByKey($removedAddressId); + } else { + $address->setParentId( + $customer->getId() + )->setStoreId( + $customer->getStoreId() + )->setIsCustomerSaveTransaction( + true + )->save(); - if (($address->getIsPrimaryBilling() || - $address->getIsDefaultBilling()) && $address->getId() != $defaultBillingId - ) { - $customer->setData('default_billing', $address->getId()); - } + if (($address->getIsPrimaryBilling() || + $address->getIsDefaultBilling()) && $address->getId() != $defaultBillingId + ) { + $customer->setData('default_billing', $address->getId()); + } - if (($address->getIsPrimaryShipping() || - $address->getIsDefaultShipping()) && $address->getId() != $defaultShippingId - ) { - $customer->setData('default_shipping', $address->getId()); + if (($address->getIsPrimaryShipping() || + $address->getIsDefaultShipping()) && $address->getId() != $defaultShippingId + ) { + $customer->setData('default_shipping', $address->getId()); + } } } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 43ae2db0c2163..bfa473480335b 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -212,6 +212,7 @@ public function save(CustomerInterface $customer, $passwordHash = null) ) { $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); } + $this->setValidationFlag($customerArr, $customerModel); $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); @@ -221,7 +222,7 @@ public function save(CustomerInterface $customer, $passwordHash = null) ) { $customer->setAddresses($delegatedNewOperation->getCustomer()->getAddresses()); } - if ($customer->getAddresses() !== null) { + if ($customer->getAddresses() !== null && !$customerModel->getData('ignore_validation_flag')) { if ($customer->getId()) { $existingAddresses = $this->getById($customer->getId())->getAddresses(); $getIdFunc = function ($address) { @@ -389,4 +390,18 @@ protected function addFilterGroupToCollection( $collection->addFieldToFilter($fields); } } + + /** + * Set ignore_validation_flag to skip model validation + * + * @param array $customerArray + * @param Customer $customerModel + * @return void + */ + private function setValidationFlag($customerArray, $customerModel) + { + if (isset($customerArray['ignore_validation_flag'])) { + $customerModel->setData('ignore_validation_flag', true); + } + } } From e3940f0de98155da20329988d5dd96d010ca3e27 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Fri, 9 Nov 2018 15:43:37 +0300 Subject: [PATCH 0578/1158] MAGETWO-96125: Points not added with New Account Email Confirmation enabled - Change template functionality --- .../Api/AccountManagementInterface.php | 8 ++++-- .../Customer/Model/AccountManagement.php | 26 ++++++++++++++----- .../Customer/Model/EmailNotification.php | 25 ++++++++++++++++-- .../email/account_new_confirmation.html | 6 +++-- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Customer/Api/AccountManagementInterface.php b/app/code/Magento/Customer/Api/AccountManagementInterface.php index 10fc2349968ea..6c1a24d5029ac 100644 --- a/app/code/Magento/Customer/Api/AccountManagementInterface.php +++ b/app/code/Magento/Customer/Api/AccountManagementInterface.php @@ -31,13 +31,15 @@ interface AccountManagementInterface * @param \Magento\Customer\Api\Data\CustomerInterface $customer * @param string $password * @param string $redirectUrl + * @param array $extensions * @return \Magento\Customer\Api\Data\CustomerInterface * @throws \Magento\Framework\Exception\LocalizedException */ public function createAccount( \Magento\Customer\Api\Data\CustomerInterface $customer, $password = null, - $redirectUrl = '' + $redirectUrl = '', + $extensions = [] ); /** @@ -48,6 +50,7 @@ public function createAccount( * @param string $hash Password hash that we can save directly * @param string $redirectUrl URL fed to welcome email templates. Can be used by templates to, for example, direct * the customer to a product they were looking at after pressing confirmation link. + * @param array $extensions * @return \Magento\Customer\Api\Data\CustomerInterface * @throws \Magento\Framework\Exception\InputException If bad input is provided * @throws \Magento\Framework\Exception\State\InputMismatchException If the provided email is already used @@ -56,7 +59,8 @@ public function createAccount( public function createAccountWithPasswordHash( \Magento\Customer\Api\Data\CustomerInterface $customer, $hash, - $redirectUrl = '' + $redirectUrl = '', + $extensions = [] ); /** diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 9173307a7d270..4b899fe486e5c 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -794,7 +794,7 @@ public function getConfirmationStatus($customerId) /** * @inheritdoc */ - public function createAccount(CustomerInterface $customer, $password = null, $redirectUrl = '') + public function createAccount(CustomerInterface $customer, $password = null, $redirectUrl = '', $extensions = []) { if ($password !== null) { $this->checkPasswordStrength($password); @@ -810,7 +810,7 @@ public function createAccount(CustomerInterface $customer, $password = null, $re } else { $hash = null; } - return $this->createAccountWithPasswordHash($customer, $hash, $redirectUrl); + return $this->createAccountWithPasswordHash($customer, $hash, $redirectUrl, $extensions); } /** @@ -818,8 +818,12 @@ public function createAccount(CustomerInterface $customer, $password = null, $re * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - public function createAccountWithPasswordHash(CustomerInterface $customer, $hash, $redirectUrl = '') - { + public function createAccountWithPasswordHash( + CustomerInterface $customer, + $hash, + $redirectUrl = '', + $extensions = [] + ) { // This logic allows an existing customer to be added to a different store. No new account is created. // The plan is to move this logic into a new method called something like 'registerAccountWithStore' if ($customer->getId()) { @@ -892,7 +896,7 @@ public function createAccountWithPasswordHash(CustomerInterface $customer, $hash $customer = $this->customerRepository->getById($customer->getId()); $newLinkToken = $this->mathRandom->getUniqueHash(); $this->changeResetPasswordLinkToken($customer, $newLinkToken); - $this->sendEmailConfirmation($customer, $redirectUrl); + $this->sendEmailConfirmation($customer, $redirectUrl, $extensions); return $customer; } @@ -920,9 +924,10 @@ public function getDefaultShippingAddress($customerId) * * @param CustomerInterface $customer * @param string $redirectUrl + * @param array $extensions * @return void */ - protected function sendEmailConfirmation(CustomerInterface $customer, $redirectUrl) + protected function sendEmailConfirmation(CustomerInterface $customer, $redirectUrl, $extensions = []) { try { $hash = $this->customerRegistry->retrieveSecureData($customer->getId())->getPasswordHash(); @@ -932,7 +937,14 @@ protected function sendEmailConfirmation(CustomerInterface $customer, $redirectU } elseif ($hash == '') { $templateType = self::NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD; } - $this->getEmailNotification()->newAccount($customer, $templateType, $redirectUrl, $customer->getStoreId()); + $this->getEmailNotification()->newAccount( + $customer, + $templateType, + $redirectUrl, + $customer->getStoreId(), + null, + $extensions + ); } catch (MailException $e) { // If we are not able to send a new account email, this should be ignored $this->logger->critical($e); diff --git a/app/code/Magento/Customer/Model/EmailNotification.php b/app/code/Magento/Customer/Model/EmailNotification.php index 4b65dcca0973f..30a9dbedde8d0 100644 --- a/app/code/Magento/Customer/Model/EmailNotification.php +++ b/app/code/Magento/Customer/Model/EmailNotification.php @@ -17,6 +17,8 @@ use Magento\Framework\Exception\LocalizedException; /** + * Class for notification customer. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class EmailNotification implements EmailNotificationInterface @@ -63,6 +65,8 @@ class EmailNotification implements EmailNotificationInterface self::NEW_ACCOUNT_EMAIL_CONFIRMATION => self::XML_PATH_CONFIRM_EMAIL_TEMPLATE, ]; + const CUSTOMER_CONFIRM_URL = 'customer/account/confirm/'; + /**#@-*/ /**#@-*/ @@ -362,6 +366,7 @@ public function passwordResetConfirmation(CustomerInterface $customer) * @param string $backUrl * @param string $storeId * @param string $sendemailStoreId + * @param array $extensions * @return void * @throws LocalizedException */ @@ -370,7 +375,8 @@ public function newAccount( $type = self::NEW_ACCOUNT_EMAIL_REGISTERED, $backUrl = '', $storeId = 0, - $sendemailStoreId = null + $sendemailStoreId = null, + $extensions = [] ) { $types = self::TEMPLATE_TYPES; @@ -388,11 +394,26 @@ public function newAccount( $customerEmailData = $this->getFullCustomerObject($customer); + $templateVars = [ + 'customer' => $customerEmailData, + 'back_url' => $backUrl, + 'store' => $store + ]; + if ($type == self::NEW_ACCOUNT_EMAIL_CONFIRMATION) { + if (empty($extensions)) { + $templateVars['url'] = self::CUSTOMER_CONFIRM_URL; + $templateVars['extensions'] = $extensions; + } else { + $templateVars['url'] = $extensions['url']; + $templateVars['extensions'] = $extensions['extension_info']; + } + } + $this->sendEmailTemplate( $customer, $types[$type], self::XML_PATH_REGISTER_EMAIL_IDENTITY, - ['customer' => $customerEmailData, 'back_url' => $backUrl, 'store' => $store], + $templateVars, $storeId ); } diff --git a/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html b/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html index 010087ace2d42..9b183d63471f3 100644 --- a/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html +++ b/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html @@ -9,7 +9,9 @@ "var this.getUrl($store, 'customer/account/confirm/', [_query:[id:$customer.id, key:$customer.confirmation, back_url:$back_url]])":"Account Confirmation URL", "var this.getUrl($store, 'customer/account/')":"Customer Account URL", "var customer.email":"Customer Email", -"var customer.name":"Customer Name" +"var customer.name":"Customer Name", +"var extensions":"Extensions", +"var url":"Url" } @--> {{template config_path="design/email/header_template"}} @@ -23,7 +25,7 @@ <table class="inner-wrapper" border="0" cellspacing="0" cellpadding="0" align="center"> <tr> <td align="center"> - <a href="{{var this.getUrl($store,'customer/account/confirm/',[_query:[id:$customer.id,key:$customer.confirmation,back_url:$back_url],_nosid:1])}}" target="_blank">{{trans "Confirm Your Account"}}</a> + <a href="{{var this.getUrl($store,$url,[_query:[id:$customer.id,key:$customer.confirmation,extensions:$extensions,back_url:$back_url],_nosid:1])}}" target="_blank">{{trans "Confirm Your Account"}}</a> </td> </tr> </table> From e767121cab5385e1ea5f36b237622eb258333566 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Fri, 9 Nov 2018 15:54:57 +0300 Subject: [PATCH 0579/1158] MAGETWO-91650: Translation not working for product alerts - Add store id for product alert --- .../ProductAlert/etc/db_schema_whitelist.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json b/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json index 234e3d14876e5..94c9d07c85015 100644 --- a/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json +++ b/app/code/Magento/ProductAlert/etc/db_schema_whitelist.json @@ -1,6 +1,7 @@ { "product_alert_price": { "column": { + "store_id": true, "alert_price_id": true, "customer_id": true, "product_id": true, @@ -9,26 +10,26 @@ "add_date": true, "last_send_date": true, "send_count": true, - "status": true, - "store_id": true + "status": true }, "index": { + "PRODUCT_ALERT_PRICE_STORE_ID": true, "PRODUCT_ALERT_PRICE_CUSTOMER_ID": true, "PRODUCT_ALERT_PRICE_PRODUCT_ID": true, - "PRODUCT_ALERT_PRICE_WEBSITE_ID": true, - "PRODUCT_ALERT_PRICE_STORE_ID": true + "PRODUCT_ALERT_PRICE_WEBSITE_ID": true }, "constraint": { + "PRODUCT_ALERT_PRICE_STORE_ID_STORE_STORE_ID": true, "PRIMARY": true, "PRODUCT_ALERT_PRICE_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID": true, "PRODUCT_ALERT_PRICE_PRODUCT_ID_CATALOG_PRODUCT_ENTITY_ENTITY_ID": true, "PRODUCT_ALERT_PRICE_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID": true, - "PRODUCT_ALERT_PRICE_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true, - "PRODUCT_ALERT_PRICE_STORE_ID_STORE_STORE_ID": true + "PRODUCT_ALERT_PRICE_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true } }, "product_alert_stock": { "column": { + "store_id": true, "alert_stock_id": true, "customer_id": true, "product_id": true, @@ -36,22 +37,21 @@ "add_date": true, "send_date": true, "send_count": true, - "status": true, - "store_id": true + "status": true }, "index": { + "PRODUCT_ALERT_STOCK_STORE_ID": true, "PRODUCT_ALERT_STOCK_CUSTOMER_ID": true, "PRODUCT_ALERT_STOCK_PRODUCT_ID": true, - "PRODUCT_ALERT_STOCK_WEBSITE_ID": true, - "PRODUCT_ALERT_STOCK_STORE_ID": true + "PRODUCT_ALERT_STOCK_WEBSITE_ID": true }, "constraint": { + "PRODUCT_ALERT_STOCK_STORE_ID_STORE_STORE_ID": true, "PRIMARY": true, "PRODUCT_ALERT_STOCK_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID": true, "PRODUCT_ALERT_STOCK_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID": true, "PRODUCT_ALERT_STOCK_PRODUCT_ID_CATALOG_PRODUCT_ENTITY_ENTITY_ID": true, - "PRODUCT_ALERT_STOCK_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true, - "PRODUCT_ALERT_STOCK_STORE_ID_STORE_STORE_ID": true + "PRODUCT_ALERT_STOCK_PRODUCT_ID_SEQUENCE_PRODUCT_SEQUENCE_VALUE": true } } } From 842324af44d362b3533a4559e7d4c8ab35b2e2be Mon Sep 17 00:00:00 2001 From: Stanislav Idolov <sidolov@magento.com> Date: Fri, 9 Nov 2018 15:02:27 +0200 Subject: [PATCH 0580/1158] magento-engcom/magento2ce#2324: Fixed Code Style Issues --- app/code/Magento/Backup/Controller/Adminhtml/Index.php | 5 ++++- .../Magento/Reports/Model/Product/Index/AbstractIndex.php | 7 ++++--- app/code/Magento/Weee/Model/Sales/Pdf/Weee.php | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index.php b/app/code/Magento/Backup/Controller/Adminhtml/Index.php index 142211fe90a44..94dca327195f3 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index.php @@ -5,6 +5,9 @@ */ namespace Magento\Backup\Controller\Adminhtml; +use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpGetActionInterface; + /** * Backup admin controller * @@ -12,7 +15,7 @@ * @api * @since 100.0.2 */ -abstract class Index extends \Magento\Backend\App\Action +abstract class Index extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php b/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php index 56991e290dec6..7337286149cc3 100644 --- a/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php +++ b/app/code/Magento/Reports/Model/Product/Index/AbstractIndex.php @@ -113,7 +113,7 @@ public function beforeSave() /** * Retrieve visitor id * - * if don't exists return current visitor id + * If don't exists return current visitor id * * @return int */ @@ -128,7 +128,7 @@ public function getVisitorId() /** * Retrieve customer id * - * if customer don't logged in return null + * If customer don't logged in return null * * @return int */ @@ -143,7 +143,7 @@ public function getCustomerId() /** * Retrieve store id * - * default return current store id + * Default return current store id * * @return int */ @@ -246,6 +246,7 @@ public function clean() /** * Add product ids to current visitor/customer log + * * @param string[] $productIds * @return $this */ diff --git a/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php b/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php index 65480047f2f05..2b8c74581d973 100644 --- a/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php +++ b/app/code/Magento/Weee/Model/Sales/Pdf/Weee.php @@ -36,6 +36,7 @@ public function __construct( /** * Check if weee total amount should be included * + * Example: * array( * $index => array( * 'amount' => $amount, @@ -43,6 +44,7 @@ public function __construct( * 'font_size'=> $font_size * ) * ) + * * @return array */ public function getTotalsForDisplay() From fea9aafd36096a92304c8f0fc3d223637d6d665d Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Fri, 9 Nov 2018 15:04:09 +0200 Subject: [PATCH 0581/1158] Adjusting the Unit Test for the isCurrent method --- .../Unit/Element/Html/Link/CurrentTest.php | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php index 909748722a081..9c720f0f48dc3 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php @@ -17,11 +17,6 @@ class CurrentTest extends \PHPUnit\Framework\TestCase */ protected $_requestMock; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $_defaultPathMock; - /** * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ @@ -32,7 +27,6 @@ protected function setUp() $this->_objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_urlBuilderMock = $this->createMock(\Magento\Framework\UrlInterface::class); $this->_requestMock = $this->createMock(\Magento\Framework\App\Request\Http::class); - $this->_defaultPathMock = $this->createMock(\Magento\Framework\App\DefaultPathInterface::class); } public function testGetUrl() @@ -60,31 +54,54 @@ public function testIsCurrentIfIsset() $this->assertTrue($link->isCurrent()); } - public function testIsCurrent() + /** + * Test if the current url is the same as link path + * + * @dataProvider linkPathProvider + * @param string $linkPath + * @param string $currentPathInfo + * @param bool $expected + * @return void + */ + public function testIsCurrent($linkPath, $currentPathInfo, $expected) { - $path = 'test/path'; - $url = 'http://example.com/a/b'; - - $this->_requestMock->expects($this->once())->method('getModuleName')->will($this->returnValue('a')); - $this->_requestMock->expects($this->once())->method('getControllerName')->will($this->returnValue('b')); - $this->_requestMock->expects($this->once())->method('getActionName')->will($this->returnValue('d')); - $this->_defaultPathMock->expects($this->atLeastOnce())->method('getPart')->will($this->returnValue('d')); - - $this->_urlBuilderMock->expects($this->at(0))->method('getUrl')->with($path)->will($this->returnValue($url)); - $this->_urlBuilderMock->expects($this->at(1))->method('getUrl')->with('a/b')->will($this->returnValue($url)); - - $this->_requestMock->expects($this->once())->method('getControllerName')->will($this->returnValue('b')); + $baseUrl = 'http://example.com/'; + $trimmed = trim($currentPathInfo, '/'); + + $this->_requestMock->expects($this->any())->method('getPathInfo')->willReturn($currentPathInfo); + $this->_urlBuilderMock->expects($this->at(0)) + ->method('getUrl') + ->with($linkPath) + ->will($this->returnValue($baseUrl . $linkPath)); + $this->_urlBuilderMock->expects($this->at(1)) + ->method('getUrl') + ->with($trimmed) + ->will($this->returnValue($baseUrl . $trimmed)); /** @var \Magento\Framework\View\Element\Html\Link\Current $link */ $link = $this->_objectManager->getObject( \Magento\Framework\View\Element\Html\Link\Current::class, [ 'urlBuilder' => $this->_urlBuilderMock, - 'request' => $this->_requestMock, - 'defaultPath' => $this->_defaultPathMock + 'request' => $this->_requestMock ] ); - $link->setPath($path); - $this->assertTrue($link->isCurrent()); + + $link->setCurrent(false); + $link->setPath($linkPath); + $this->assertEquals($expected, $link->isCurrent()); + } + + /** + * @return array + */ + public function linkPathProvider() + { + return [ + ['test/index', '/test/index/', true], + ['test/index/index', '/test/index/index/', true], + ['test/route', '/test/index/', false], + ['test/index', '/test/', false] + ]; } public function testIsCurrentFalse() From 023a39177eb8889f291f92f3651c22c4c28c2908 Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Fri, 9 Nov 2018 15:18:52 +0200 Subject: [PATCH 0582/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - fix issue with enabled Braintree and shipping tax class --- ...thOnlinePaymentIncludingTaxAndDiscount.xml | 5 +++- .../Mftf/ActionGroup/AdminTaxActionGroup.xml | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml index a7c0e8f62544e..7c0a503e7bb4b 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml @@ -48,6 +48,9 @@ <!--Delete Cart Price Rule--> <actionGroup ref="AdminDeleteCartPriceRuleForRetailerActionGroup" stepKey="deleteSalesRule"/> + <!--Set to default configuration Tax Shipping Class--> + <actionGroup ref="setDefaultShippingTaxClass" stepKey="setdefaultClass"/> + <!--Delete Simple Sub Category--> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> @@ -58,7 +61,7 @@ <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> <!-- Rollback Braintree to Default --> - <createData entity="DefaultBraintreeConfig" stepKey="DefaultBraintreeConfig"/> + <createData entity="RollBackCustomBraintreeConfigurationData" stepKey="rollbackBraintreeConfig"/> <!--Delete Customer--> <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml index 3009fa1fc8a25..4f724fb0047e6 100644 --- a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml @@ -145,6 +145,32 @@ <see stepKey="seeSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the configuration."/> </actionGroup> + <actionGroup name="setDefaultShippingTaxClass"> + <!--Select Configuration menu from Store--> + <click selector="{{AdminMenuSection.stores}}" stepKey="clickOnSTORES" /> + <waitForPageLoad stepKey="waitForConfiguration" time="5"/> + <click selector="{{StoresSubmenuSection.configuration}}" stepKey="clickOnConfigurations"/> + <waitForPageLoad stepKey="waitForSales" time="5"/> + <!--Double click the same to fix flaky issue with redirection to Dashboard--> + <click selector="{{AdminMenuSection.stores}}" stepKey="clickOnSTORES1" /> + <waitForPageLoad stepKey="waitForConfiguration1" time="5"/> + <click selector="{{StoresSubmenuSection.configuration}}" stepKey="clickOnConfigurations1"/> + <waitForPageLoad stepKey="waitForSales1" time="5"/> + <!--Change default tax class for Shipping on Taxable Goods--> + <click selector="{{ConfigurationListSection.sales}}" stepKey="clickOnSales" /> + <waitForPageLoad stepKey="waitForPaymentMethods" time="5"/> + <click selector="{{AdminConfigureTaxSection.salesTax}}" stepKey="clickOnTax"/> + <waitForPageLoad stepKey="waitForTax" time="5"/> + <seeElement selector="{{AdminConfigureTaxSection.taxClasses}}" stepKey="taxClassSectionC"/> + <click selector="{{AdminConfigureTaxSection.taxShippingClassSystem}}" stepKey="checkSystemDefaultValue"/> + <click selector="{{AdminConfigureTaxSection.taxClasses}}" stepKey="closeTaxClassSection"/> + <!-- Save the settings --> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click stepKey="saveTaxOptions" selector="{{AdminCategoryMainActionsSection.SaveButton}}"/> + <waitForPageLoad stepKey="waitForTaxSaved"/> + <see stepKey="seeSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the configuration."/> + </actionGroup> + <!--Add Product Tax Class--> <actionGroup name="addProductTaxClass"> <arguments> From 40b2ebb83674897d81a2e98d309403ca7d5e75f1 Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Fri, 9 Nov 2018 18:15:52 +0400 Subject: [PATCH 0583/1158] MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages - Updated element locator for test --- .../Mftf/Section/AdminProductFormGroupedProductsSection.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml index f5549f26bfd56..547c856d144c8 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml @@ -11,9 +11,9 @@ <section name="AdminProductFormGroupedProductsSection"> <element name="toggleGroupedProduct" type="button" selector="div[data-index=grouped] .admin__collapsible-title"/> <element name="addProductsToGroup" type="button" selector="button[data-index='grouped_products_button']" timeout="30"/> - <element name="nextActionButton" type="button" selector=".admin__field > .admin__field-control > .admin__control-table-pagination > .admin__data-grid-pager > .action-next"/> - <element name="previousActionButton" type="button" selector=".admin__field > .admin__field-control > .admin__control-table-pagination > .admin__data-grid-pager > .action-previous"/> + <element name="nextActionButton" type="button" selector="//*[@data-index='grouped']//*[@class='action-next']"/> + <element name="previousActionButton" type="button" selector="//*[@data-index='grouped']//*[@class='action-previous']"/> <element name="positionProduct" type="input" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[10]//input[@class='position-widget-input']" parameterized="true"/> <element name="nameProductFromGrid" type="text" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[4]//*[@class='admin__field-control']//span" parameterized="true"/> </section> -</sections> \ No newline at end of file +</sections> From e9f2b802a6127811867e193e3b792f7f8a0d1051 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Fri, 9 Nov 2018 09:44:47 -0600 Subject: [PATCH 0584/1158] MAGETWO-96231: All pages in magento are broken on Nginx (MAGE_DIRS errors) - Added check for array existence --- pub/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pub/index.php b/pub/index.php index 90b4778265447..612e190719053 100644 --- a/pub/index.php +++ b/pub/index.php @@ -26,7 +26,7 @@ $params = $_SERVER; $params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = array_replace_recursive( - $params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS], + $params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] ?? [], [ DirectoryList::PUB => [DirectoryList::URL_PATH => ''], DirectoryList::MEDIA => [DirectoryList::URL_PATH => 'media'], From 6a20b98dd369a64ddfa6a08ea5e4f71ba94d8a50 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Fri, 9 Nov 2018 18:01:13 +0200 Subject: [PATCH 0585/1158] GraphQl-45: Product textarea field format -- Update benchmarks scenarios according to updated GraphQL Schema --- setup/performance-toolkit/benchmark.jmx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 37e07d1319572..a13fe47a86532 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -40763,7 +40763,7 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(\n filter: {\n price: {gt: \"10\"}\n or: {\n sku:{like:\"%Product%\"}\n name:{like:\"%Configurable Product%\"}\n }\n }\n pageSize: 200\n currentPage: 1\n sort: {\n price: ASC\n name:DESC\n }\n ) {\n total_count\n items {\n attribute_set_id\n country_of_manufacture\n created_at\n description\n gift_message_available\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n short_description\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n \t... on PhysicalProductInterface {\n \tweight\n \t}\n }\n page_info {\n page_size\n current_page\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(\n filter: {\n price: {gt: \"10\"}\n or: {\n sku:{like:\"%Product%\"}\n name:{like:\"%Configurable Product%\"}\n }\n }\n pageSize: 200\n currentPage: 1\n sort: {\n price: ASC\n name:DESC\n }\n ) {\n total_count\n items {\n attribute_set_id\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n short_description {\n html\n }\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n \t... on PhysicalProductInterface {\n \tweight\n \t}\n }\n page_info {\n page_size\n current_page\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -40820,7 +40820,7 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: { eq: \"${simple_product_sku}\" } })\n {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: { eq: \"${simple_product_sku}\" } })\n {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -40896,7 +40896,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: {eq:\"${configurable_product_sku}\"} }) {\n total_count\n items {\n ... on PhysicalProductInterface {\n weight\n }\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: {eq:\"${configurable_product_sku}\"} }) {\n total_count\n items {\n ... on PhysicalProductInterface {\n weight\n }\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -40965,7 +40965,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(\n search: \"configurable\"\n filter: {price: {gteq: \"1\"} }\n ) {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t\t}\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(\n search: \"configurable\"\n filter: {price: {gteq: \"1\"} }\n ) {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t\t}\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -41025,7 +41025,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(search: \"configurable\") {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t\t}\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(search: \"configurable\") {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t\t}\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -41085,7 +41085,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(search: \"color\") {\n filters {\n name\n filter_items_count\n request_var\n filter_items {\n label\n value_string\n items_count\n ... on SwatchLayerFilterItemInterface {\n swatch_data {\n type\n value\n }\n }\n }\n }\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n weight\n }\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(search: \"color\") {\n filters {\n name\n filter_items_count\n request_var\n filter_items {\n label\n value_string\n items_count\n ... on SwatchLayerFilterItemInterface {\n swatch_data {\n type\n value\n }\n }\n }\n }\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n weight\n }\n ... on ConfigurableProduct {\n configurable_options {\n id\n attribute_id\n label\n position\n use_default\n attribute_code\n values {\n value_index\n label\n store_label\n default_label\n use_default_value\n }\n product_id\n }\n variants {\n product {\n ... on PhysicalProductInterface {\n weight\n }\n sku\n color\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n\n\n }\n attributes {\n label\n code\n value_index\n }\n }\n }\n }\n }\n}","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -41145,7 +41145,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\nproducts(filter: {sku: {eq:\"${bundle_product_sku}\"} }) {\n total_count\n items {\n ... on PhysicalProductInterface {\n weight\n }\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on BundleProduct {\n weight\n price_view\n dynamic_price\n dynamic_sku\n ship_bundle_items\n dynamic_weight\n items {\n option_id\n title\n required\n type\n position\n sku\n options {\n id\n qty\n position\n is_default\n price\n price_type\n can_change_quantity\n product {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n }\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\nproducts(filter: {sku: {eq:\"${bundle_product_sku}\"} }) {\n total_count\n items {\n ... on PhysicalProductInterface {\n weight\n }\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on BundleProduct {\n weight\n price_view\n dynamic_price\n dynamic_sku\n ship_bundle_items\n dynamic_weight\n items {\n option_id\n title\n required\n type\n position\n sku\n options {\n id\n qty\n position\n is_default\n price\n price_type\n can_change_quantity\n product {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n }\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -41214,7 +41214,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: { eq: \"${downloadable_product_sku}\" } })\n {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t }\n ... on DownloadableProduct {\n links_purchased_separately\n links_title\n downloadable_product_samples {\n id\n title\n sort_order\n sample_type\n sample_file\n sample_url\n }\n downloadable_product_links {\n id\n title\n sort_order\n is_shareable\n price\n number_of_downloads\n link_type\n sample_type\n sample_file\n sample_url\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: { eq: \"${downloadable_product_sku}\" } })\n {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t }\n ... on DownloadableProduct {\n links_purchased_separately\n links_title\n downloadable_product_samples {\n id\n title\n sort_order\n sample_type\n sample_file\n sample_url\n }\n downloadable_product_links {\n id\n title\n sort_order\n is_shareable\n price\n number_of_downloads\n link_type\n sample_type\n sample_file\n sample_url\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -41301,7 +41301,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: { eq: \"${virtual_product_sku}\" } })\n {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\n products(filter: {sku: { eq: \"${virtual_product_sku}\" } })\n {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on PhysicalProductInterface {\n \t\t\tweight\n \t\t }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -41368,7 +41368,7 @@ if (totalCount == null) { <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"query":"{\nproducts(filter: {sku: {eq:\"${grouped_product_sku}\"} }) {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on GroupedProduct {\n weight\n items {\n qty\n position\n product {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.value">{"query":"{\nproducts(filter: {sku: {eq:\"${grouped_product_sku}\"} }) {\n total_count\n items {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n ... on GroupedProduct {\n weight\n items {\n qty\n position\n product {\n attribute_set_id\n categories\n {\n id\n position\n }\n country_of_manufacture\n created_at\n description {\n html\n }\n gift_message_available\n id\n image\n {\n url\n label\n }\n meta_description\n meta_keyword\n meta_title\n media_gallery_entries\n {\n disabled\n file\n id\n label\n media_type\n position\n types\n content\n {\n base64_encoded_data\n type\n name\n }\n video_content\n {\n media_type\n video_description\n video_metadata\n video_provider\n video_title\n video_url\n }\n }\n name\n new_from_date\n new_to_date\n options_container\n ... on CustomizableProductInterface {\n options\n {\n title\n required\n sort_order\n }\n }\n \n price {\n minimalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n maximalPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n regularPrice {\n amount {\n value\n currency\n }\n adjustments {\n amount {\n value\n currency\n }\n code\n description\n }\n }\n }\n product_links\n {\n link_type\n linked_product_sku\n linked_product_type\n position\n sku\n }\n short_description {\n html\n }\n sku\n small_image\n {\n url\n label\n }\n special_from_date\n special_price\n special_to_date\n swatch_image\n thumbnail\n {\n url\n label\n }\n tier_price\n tier_prices\n {\n customer_group_id\n percentage_value\n qty\n value\n website_id\n }\n type_id\n updated_at\n url_key\n url_path\n websites { id name code sort_order default_group_id is_default }\n }\n }\n }\n }\n }\n}\n","variables":null,"operationName":null}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> From 0e8cd9ffc0b0ce1da6d3731fb4b21b68b40b5747 Mon Sep 17 00:00:00 2001 From: NazarKlovanych <nazarn96@gmail.com> Date: Fri, 9 Nov 2018 18:07:18 +0200 Subject: [PATCH 0586/1158] Calling getCurrentUrl on Store will wrongly add "___store" --- app/code/Magento/Store/Model/Store.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index af25957257421..04e98ed88db23 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1164,11 +1164,12 @@ public function isDefault() * Retrieve current url for store * * @param bool $fromStore + * @param bool $clearUrl * @return string * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - public function getCurrentUrl($fromStore = true) + public function getCurrentUrl($fromStore = true, $clearUrl = false) { $sidQueryParam = $this->_sidResolver->getSessionIdQueryParam($this->_getSession()); $requestString = $this->_url->escape(ltrim($this->_request->getRequestString(), '/')); @@ -1217,6 +1218,10 @@ public function getCurrentUrl($fromStore = true) $currentUrlQueryParams = array_merge($requestString, $storeParsedQuery); + if ($clearUrl !== false) { + $currentUrlQueryParams = false; + } + $currentUrl = $storeParsedUrl['scheme'] . '://' . $storeParsedUrl['host'] From a9e86656de5a821497db3f046f127d3ca83dffa8 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Fri, 9 Nov 2018 10:11:19 -0600 Subject: [PATCH 0587/1158] MQE-1339: Bump MFTF version in Magento - Repulled origin lock file, updated MFTF in lock --- composer.lock | 156 +++++++++++++++++++++++++------------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/composer.lock b/composer.lock index 7a23eee0e178b..3565ab2420e05 100644 --- a/composer.lock +++ b/composer.lock @@ -257,16 +257,16 @@ }, { "name": "composer/composer", - "version": "1.7.3", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "e965b9aaa8854c3067f1ed2ae45f436572d73eb7" + "reference": "576aab9b5abb2ed11a1c52353a759363216a4ad2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/e965b9aaa8854c3067f1ed2ae45f436572d73eb7", - "reference": "e965b9aaa8854c3067f1ed2ae45f436572d73eb7", + "url": "https://api.github.com/repos/composer/composer/zipball/576aab9b5abb2ed11a1c52353a759363216a4ad2", + "reference": "576aab9b5abb2ed11a1c52353a759363216a4ad2", "shasum": "" }, "require": { @@ -333,7 +333,7 @@ "dependency", "package" ], - "time": "2018-11-01T09:05:06+00:00" + "time": "2018-08-16T14:57:12+00:00" }, { "name": "composer/semver", @@ -399,16 +399,16 @@ }, { "name": "composer/spdx-licenses", - "version": "1.5.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2" + "reference": "cb17687e9f936acd7e7245ad3890f953770dec1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2", - "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/cb17687e9f936acd7e7245ad3890f953770dec1b", + "reference": "cb17687e9f936acd7e7245ad3890f953770dec1b", "shasum": "" }, "require": { @@ -456,7 +456,7 @@ "spdx", "validator" ], - "time": "2018-11-01T09:45:54+00:00" + "time": "2018-04-30T10:33:04+00:00" }, { "name": "composer/xdebug-handler", @@ -919,16 +919,16 @@ }, { "name": "monolog/monolog", - "version": "1.24.0", + "version": "1.23.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", "shasum": "" }, "require": { @@ -993,7 +993,7 @@ "logging", "psr-3" ], - "time": "2018-11-05T09:00:11+00:00" + "time": "2017-06-19T01:22:40+00:00" }, { "name": "oyejorge/less.php", @@ -1375,16 +1375,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "2.0.12", + "version": "2.0.11", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "8814dc7841db159daed0b32c2b08fb7e03c6afe7" + "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/8814dc7841db159daed0b32c2b08fb7e03c6afe7", - "reference": "8814dc7841db159daed0b32c2b08fb7e03c6afe7", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7053f06f91b3de78e143d430e55a8f7889efc08b", + "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b", "shasum": "" }, "require": { @@ -1463,7 +1463,7 @@ "x.509", "x509" ], - "time": "2018-11-04T05:45:48+00:00" + "time": "2018-04-15T16:55:05+00:00" }, { "name": "psr/container", @@ -1834,16 +1834,16 @@ }, { "name": "symfony/console", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "432122af37d8cd52fba1b294b11976e0d20df595" + "reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/432122af37d8cd52fba1b294b11976e0d20df595", - "reference": "432122af37d8cd52fba1b294b11976e0d20df595", + "url": "https://api.github.com/repos/symfony/console/zipball/dc7122fe5f6113cfaba3b3de575d31112c9aa60b", + "reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b", "shasum": "" }, "require": { @@ -1898,20 +1898,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:30:44+00:00" + "time": "2018-10-03T08:15:46+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "552541dad078c85d9414b09c041ede488b456cd5" + "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/552541dad078c85d9414b09c041ede488b456cd5", - "reference": "552541dad078c85d9414b09c041ede488b456cd5", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bfb30c2ad377615a463ebbc875eba64a99f6aa3e", + "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e", "shasum": "" }, "require": { @@ -1961,20 +1961,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-10-10T13:52:42+00:00" + "time": "2018-07-26T09:10:45+00:00" }, { "name": "symfony/filesystem", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981" + "reference": "596d12b40624055c300c8b619755b748ca5cf0b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd7bd6535beb1f0a0a9e3ee960666d0598546981", - "reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/596d12b40624055c300c8b619755b748ca5cf0b5", + "reference": "596d12b40624055c300c8b619755b748ca5cf0b5", "shasum": "" }, "require": { @@ -2011,11 +2011,11 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-10-30T13:18:25+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "symfony/finder", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -2064,7 +2064,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -2122,16 +2122,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.10.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", "shasum": "" }, "require": { @@ -2177,20 +2177,20 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/process", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3e83acef94d979b1de946599ef86b3a352abcdc9" + "reference": "ee33c0322a8fee0855afcc11fff81e6b1011b529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3e83acef94d979b1de946599ef86b3a352abcdc9", - "reference": "3e83acef94d979b1de946599ef86b3a352abcdc9", + "url": "https://api.github.com/repos/symfony/process/zipball/ee33c0322a8fee0855afcc11fff81e6b1011b529", + "reference": "ee33c0322a8fee0855afcc11fff81e6b1011b529", "shasum": "" }, "require": { @@ -2226,7 +2226,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-10-14T20:48:13+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "tedivm/jshrink", @@ -8228,7 +8228,7 @@ }, { "name": "symfony/browser-kit", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", @@ -8285,16 +8285,16 @@ }, { "name": "symfony/config", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "991fec8bbe77367fc8b48ecbaa8a4bd6e905a238" + "reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/991fec8bbe77367fc8b48ecbaa8a4bd6e905a238", - "reference": "991fec8bbe77367fc8b48ecbaa8a4bd6e905a238", + "url": "https://api.github.com/repos/symfony/config/zipball/b3d4d7b567d7a49e6dfafb6d4760abc921177c96", + "reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96", "shasum": "" }, "require": { @@ -8344,11 +8344,11 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:09:42+00:00" + "time": "2018-09-08T13:24:10+00:00" }, { "name": "symfony/css-selector", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -8401,16 +8401,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e72ee2c23d952e4c368ee98610fa22b79b89b483" + "reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e72ee2c23d952e4c368ee98610fa22b79b89b483", - "reference": "e72ee2c23d952e4c368ee98610fa22b79b89b483", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f6b9d893ad28aefd8942dc0469c8397e2216fe30", + "reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30", "shasum": "" }, "require": { @@ -8468,11 +8468,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-10-31T10:54:16+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "symfony/dom-crawler", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", @@ -8529,16 +8529,16 @@ }, { "name": "symfony/http-foundation", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "82d494c1492b0dd24bbc5c2d963fb02eb44491af" + "reference": "d528136617ff24f530e70df9605acc1b788b08d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/82d494c1492b0dd24bbc5c2d963fb02eb44491af", - "reference": "82d494c1492b0dd24bbc5c2d963fb02eb44491af", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d528136617ff24f530e70df9605acc1b788b08d4", + "reference": "d528136617ff24f530e70df9605acc1b788b08d4", "shasum": "" }, "require": { @@ -8579,11 +8579,11 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:09:42+00:00" + "time": "2018-10-03T08:48:45+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", @@ -8637,16 +8637,16 @@ }, { "name": "symfony/polyfill-php70", - "version": "v1.10.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" + "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934", + "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934", "shasum": "" }, "require": { @@ -8692,20 +8692,20 @@ "portable", "shim" ], - "time": "2018-09-21T06:26:08+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.10.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631" + "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", - "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/95c50420b0baed23852452a7f0c7b527303ed5ae", + "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae", "shasum": "" }, "require": { @@ -8747,11 +8747,11 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/stopwatch", - "version": "v4.1.7", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -8800,7 +8800,7 @@ }, { "name": "symfony/yaml", - "version": "v3.4.18", + "version": "v3.4.17", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", From 45d3742f7a7a3104dc756350c854da18e02a6189 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Fri, 9 Nov 2018 18:50:33 +0200 Subject: [PATCH 0588/1158] GraphQl-45: Product textarea field format -- Update benchmarks scenarios according to updated GraphQL Schema --- .../Magento/GraphQl/Catalog/UrlRewritesTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/UrlRewritesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/UrlRewritesTest.php index c39b32e4bfa4f..43796d780646c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/UrlRewritesTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/UrlRewritesTest.php @@ -33,8 +33,10 @@ public function testProductWithNoCategoriesAssigned() items { name, sku, - description, - url_rewrites { + description { + html + } + url_rewrites { url, parameters { name, @@ -87,8 +89,10 @@ public function testProductWithOneCategoryAssigned() items { name, sku, - description, - url_rewrites { + description { + html + } + url_rewrites { url, parameters { name, From 493e5b6f7448b0eb42829db2dcd424acf180cdf8 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Fri, 9 Nov 2018 11:06:12 -0600 Subject: [PATCH 0589/1158] MAGETWO-95212: Dynamic block call to getCurrentUrl method is returning ajax request value - Fixed product compare link --- app/code/Magento/Catalog/Helper/Product/Compare.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Helper/Product/Compare.php b/app/code/Magento/Catalog/Helper/Product/Compare.php index 90d98874e00cb..d6d35c5c76dd8 100644 --- a/app/code/Magento/Catalog/Helper/Product/Compare.php +++ b/app/code/Magento/Catalog/Helper/Product/Compare.php @@ -166,7 +166,15 @@ public function getListUrl() */ public function getPostDataParams($product) { - return $this->postHelper->getPostData($this->getAddUrl(), ['product' => $product->getId()]); + $params = ['product' => $product->getId()]; + $requestingPageUrl = $this->_getRequest()->getParam('requesting_page_url'); + + if (!empty($requestingPageUrl)) { + $encodedUrl = $this->urlEncoder->encode($requestingPageUrl); + $params[\Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED] = $encodedUrl; + } + + return $this->postHelper->getPostData($this->getAddUrl(), $params); } /** From 6c8dfe2c4f2556a2c182f9042fab93ff0d5cc75d Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@adobe.com> Date: Fri, 9 Nov 2018 11:06:40 -0600 Subject: [PATCH 0590/1158] MAGETWO-89232: Validation error appears if duplicate product twice - CR comment --- .../Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml index 8dffc3d352a7b..6658ad36d7150 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductDuplicateUrlkeyTest.xml @@ -43,7 +43,7 @@ <test name="AdminCreateProductDuplicateProductTest"> <annotations> <features value="Catalog"/> - <stories value="Errors"/> + <stories value="Validation Errors"/> <title value="No validation errors when trying to duplicate product twice"/> <description value="No validation errors when trying to duplicate product twice"/> <severity value="MAJOR"/> From 2283662f6a0a3b2c0d9d7a27c1a440f60b562c27 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Fri, 9 Nov 2018 11:40:32 -0600 Subject: [PATCH 0591/1158] MAGETWO-95212: Dynamic block call to getCurrentUrl method is returning ajax request value - Added selector --- .../CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml index 4e79334a94cd3..03bef8ffa3b7d 100644 --- a/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Section/ProductListWidgetSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="ProductListWidgetSection"> <element name="AddToCartByName" type="button" selector="//*[contains(@class,'product-item-info')][descendant::a[contains(text(), '{{arg1}}')]]//button[contains(@class,'tocart')]" parameterized="true"/> + <element name="AddToCompareByName" type="button" selector="//*[contains(@class,'product-item-info')][descendant::a[contains(text(), '{{arg1}}')]]//button[contains(@class,'tocompare')]" parameterized="true"/> </section> </sections> From bfcf6249bb0e26d835e8bace4764c8cadfe1568b Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Fri, 9 Nov 2018 13:55:29 -0600 Subject: [PATCH 0592/1158] MQE-1339: Bump MFTF version in Magento - Fix flaky actionGroup --- .../ChangeStatusProductUsingProductGridActionGroup.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml b/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml index 9698f9cef4219..1961b1002df70 100644 --- a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml +++ b/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml @@ -27,6 +27,7 @@ <click selector="{{AdminProductGridSection.changeStatus('status')}}" stepKey="clickChangeStatusDisabled"/> <waitForPageLoad stepKey="waitForDisable"/> <see selector="{{AdminMessagesSection.success}}" userInput="A total of 1 record(s) have been updated." stepKey="seeSuccessMessage"/> + <waitForLoadingMaskToDisappear stepKey="waitForMaskToDisappear"/> <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial2"/> </actionGroup> </actionGroups> From 4879fae86d13f421a8dbdb95fb47c784c1f50e41 Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Fri, 9 Nov 2018 15:59:15 -0600 Subject: [PATCH 0593/1158] MAGETWO-95892: Selecting Gift Options for items redirects on 404 Page --- app/code/Magento/Checkout/Controller/Cart/UpdatePost.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php index 9f0dcc6d9c18f..be84dcd76bb88 100644 --- a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php +++ b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php @@ -8,8 +8,9 @@ use Magento\Checkout\Model\Cart\RequestQuantityProcessor; use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; -class UpdatePost extends \Magento\Checkout\Controller\Cart implements HttpPostActionInterface +class UpdatePost extends \Magento\Checkout\Controller\Cart implements HttpPostActionInterface, HttpGetActionInterface { /** * @var RequestQuantityProcessor From 15dc79bea4a604a22a68e3a14fbd643336b3a400 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Fri, 9 Nov 2018 16:04:29 -0600 Subject: [PATCH 0594/1158] ENGCOM-3421: Magento 2.3 Fix Notice and Exception while adding image to product programmatically #18952 - Fixed docblocks --- .../Magento/Catalog/Model/Product/Gallery/Processor.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index 9cd5073f4357c..0912324745360 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -88,6 +88,8 @@ public function __construct( } /** + * Return media_gallery attribute + * * @return \Magento\Catalog\Api\Data\ProductAttributeInterface * @since 101.0.0 */ @@ -383,7 +385,8 @@ public function setMediaAttribute(\Magento\Catalog\Model\Product $product, $medi } /** - * get media attribute codes + * Get media attribute codes + * * @return array * @since 101.0.0 */ @@ -393,6 +396,8 @@ public function getMediaAttributeCodes() } /** + * Trim .tmp ending from filename + * * @param string $file * @return string * @since 101.0.0 @@ -514,7 +519,6 @@ public function getAffectedFields($object) /** * Attribute value is not to be saved in a conventional way, separate table is used to store the complex value * - * {@inheritdoc} * @since 101.0.0 */ public function isScalar() From 5c04cf909f94d8a5afa1cb74dbaed5b0ccf8b955 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Fri, 9 Nov 2018 16:21:04 -0600 Subject: [PATCH 0595/1158] #2324: Skipping flaky test --- .../Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml index b87ab626d3970..0b2809dfc3543 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml @@ -251,6 +251,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-297"/> <group value="Tax"/> + <skip> + <issueId value="MAGETWO-96266"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> From e827b3220c12cc8e793e0486cd9425e4ca4c2853 Mon Sep 17 00:00:00 2001 From: Vova Yatsyuk <vova.yatsyuk@gmail.com> Date: Sat, 10 Nov 2018 11:43:05 +0200 Subject: [PATCH 0596/1158] Allow to read HTTP/2 response header. The issue is HTTP/2 sends the following headers `HTTP/2 200`, `HTTP/2 401` and so on. It doesn't have third parameter like HTTP/1.1 has: `HTTP/2 200 OK` --- lib/internal/Magento/Framework/HTTP/Client/Curl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/HTTP/Client/Curl.php b/lib/internal/Magento/Framework/HTTP/Client/Curl.php index d1dfafdeb2adb..0ac65a420ddcf 100644 --- a/lib/internal/Magento/Framework/HTTP/Client/Curl.php +++ b/lib/internal/Magento/Framework/HTTP/Client/Curl.php @@ -438,7 +438,7 @@ protected function parseHeaders($ch, $data) { if ($this->_headerCount == 0) { $line = explode(" ", trim($data), 3); - if (count($line) != 3) { + if (count($line) < 2) { $this->doError("Invalid response line returned from server: " . $data); } $this->_responseStatus = (int)$line[1]; From 57fcc1b24c4c582a96930ff7465e5f74417f2bcc Mon Sep 17 00:00:00 2001 From: Vladyslav Podorozhnyi <v.podorozhnyi@ism-ukraine.com> Date: Sat, 10 Nov 2018 11:46:07 +0200 Subject: [PATCH 0597/1158] =?UTF-8?q?magento/magento2#17833:=C2=A0=20Child?= =?UTF-8?q?=20theme=20does=20not=20inherit=20translations=20from=20parent?= =?UTF-8?q?=20theme=20-=20forward=20port=20unit=20tests=20from=202.2-devel?= =?UTF-8?q?op=20branch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Framework/Test/Unit/TranslateTest.php | 371 ++++++++++++++++++ lib/internal/Magento/Framework/Translate.php | 4 +- 2 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 lib/internal/Magento/Framework/Test/Unit/TranslateTest.php diff --git a/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php b/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php new file mode 100644 index 0000000000000..6a6407c97a95f --- /dev/null +++ b/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php @@ -0,0 +1,371 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Test\Unit; + +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\Translate; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class TranslateTest extends \PHPUnit\Framework\TestCase +{ + /** @var Translate */ + protected $translate; + + /** @var \Magento\Framework\View\DesignInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $viewDesign; + + /** @var \Magento\Framework\Cache\FrontendInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $cache; + + /** @var \Magento\Framework\View\FileSystem|\PHPUnit_Framework_MockObject_MockObject */ + protected $viewFileSystem; + + /** @var \Magento\Framework\Module\ModuleList|\PHPUnit_Framework_MockObject_MockObject */ + protected $moduleList; + + /** @var \Magento\Framework\Module\Dir\Reader|\PHPUnit_Framework_MockObject_MockObject */ + protected $modulesReader; + + /** @var \Magento\Framework\App\ScopeResolverInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $scopeResolver; + + /** @var \Magento\Framework\Translate\ResourceInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $resource; + + /** @var \Magento\Framework\Locale\ResolverInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $locale; + + /** @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject */ + protected $appState; + + /** @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject */ + protected $filesystem; + + /** @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $request; + + /** @var \Magento\Framework\File\Csv|\PHPUnit_Framework_MockObject_MockObject */ + protected $csvParser; + + /** @var \Magento\Framework\App\Language\Dictionary|\PHPUnit_Framework_MockObject_MockObject */ + protected $packDictionary; + + /** @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $directory; + + /** @var \Magento\Framework\Filesystem\DriverInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $fileDriver; + + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->viewDesign = $this->createMock(\Magento\Framework\View\DesignInterface::class); + $this->cache = $this->createMock(\Magento\Framework\Cache\FrontendInterface::class); + $this->viewFileSystem = $this->createMock(\Magento\Framework\View\FileSystem::class); + $this->moduleList = $this->createMock(\Magento\Framework\Module\ModuleList::class); + $this->modulesReader = $this->createMock(\Magento\Framework\Module\Dir\Reader::class); + $this->scopeResolver = $this->createMock(\Magento\Framework\App\ScopeResolverInterface::class); + $this->resource = $this->createMock(\Magento\Framework\Translate\ResourceInterface::class); + $this->locale = $this->createMock(\Magento\Framework\Locale\ResolverInterface::class); + $this->appState = $this->createMock(\Magento\Framework\App\State::class); + $this->request = $this->getMockForAbstractClass( + \Magento\Framework\App\RequestInterface::class, + [], + '', + false, + false, + true, + ['getParam', 'getControllerModule'] + ); + $this->csvParser = $this->createMock(\Magento\Framework\File\Csv::class); + $this->packDictionary = $this->createMock(\Magento\Framework\App\Language\Dictionary::class); + $this->directory = $this->createMock(\Magento\Framework\Filesystem\Directory\ReadInterface::class); + $filesystem = $this->createMock(\Magento\Framework\Filesystem::class); + $filesystem->expects($this->once())->method('getDirectoryRead')->will($this->returnValue($this->directory)); + $this->fileDriver = $this->createMock(\Magento\Framework\Filesystem\DriverInterface::class); + + $this->translate = new Translate( + $this->viewDesign, + $this->cache, + $this->viewFileSystem, + $this->moduleList, + $this->modulesReader, + $this->scopeResolver, + $this->resource, + $this->locale, + $this->appState, + $filesystem, + $this->request, + $this->csvParser, + $this->packDictionary, + $this->fileDriver + ); + + $serializerMock = $this->createMock(SerializerInterface::class); + $serializerMock->method('serialize') + ->willReturnCallback(function ($data) { + return json_encode($data); + }); + $serializerMock->method('unserialize') + ->willReturnCallback(function ($string) { + return json_decode($string, true); + }); + $objectManager->setBackwardCompatibleProperty( + $this->translate, + 'serializer', + $serializerMock + ); + } + + /** + * @param string $area + * @param bool $forceReload + * @param array $cachedData + * @dataProvider dataProviderLoadDataCachedTranslation + */ + public function testLoadDataCachedTranslation($area, $forceReload, $cachedData) + { + $this->expectsSetConfig('Magento/luma'); + + $this->cache->expects($this->once()) + ->method('load') + ->will($this->returnValue(json_encode($cachedData))); + + $this->appState->expects($this->exactly($area ? 0 : 1)) + ->method('getAreaCode') + ->will($this->returnValue('frontend')); + + $this->translate->loadData($area, $forceReload); + $this->assertEquals($cachedData, $this->translate->getData()); + } + + /** + * @return array + */ + public function dataProviderLoadDataCachedTranslation() + { + $cachedData = ['cached 1' => 'translated 1', 'cached 2' => 'translated 2']; + return [ + ['adminhtml', false, $cachedData], + ['frontend', false, $cachedData], + [null, false, $cachedData], + ]; + } + + /** + * @param string $area + * @param bool $forceReload + * @dataProvider dataProviderForTestLoadData + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function testLoadData($area, $forceReload) + { + $this->expectsSetConfig('Magento/luma'); + + $this->appState->expects($this->exactly($area ? 0 : 1)) + ->method('getAreaCode') + ->will($this->returnValue('frontend')); + + $this->cache->expects($this->exactly($forceReload ? 0 : 1)) + ->method('load') + ->will($this->returnValue(false)); + + $this->directory->expects($this->any())->method('isExist')->will($this->returnValue(true)); + + // _loadModuleTranslation() + $modules = ['some_module', 'other_module', 'another_module', 'current_module']; + $this->request->expects($this->any()) + ->method('getControllerModule') + ->willReturn('current_module'); + $this->moduleList->expects($this->once())->method('getNames')->will($this->returnValue($modules)); + $moduleData = [ + 'module original' => 'module translated', + 'module theme' => 'module-theme original translated', + 'module pack' => 'module-pack original translated', + 'module db' => 'module-db original translated', + ]; + $this->modulesReader->expects($this->any())->method('getModuleDir')->will($this->returnValue('/app/module')); + $themeData = [ + 'theme original' => 'theme translated', + 'module theme' => 'theme translated overwrite', + 'module pack' => 'theme-pack translated overwrite', + 'module db' => 'theme-db translated overwrite', + ]; + $this->csvParser->expects($this->any()) + ->method('getDataPairs') + ->will( + $this->returnValueMap( + [ + ['/app/module/en_US.csv', 0, 1, $moduleData], + ['/app/module/en_GB.csv', 0, 1, $moduleData], + ['/theme.csv', 0, 1, $themeData], + ] + ) + ); + $this->fileDriver->expects($this->any()) + ->method('isExists') + ->will( + $this->returnValueMap( + [ + ['/app/module/en_US.csv', true], + ['/app/module/en_GB.csv', true], + ['/theme.csv', true], + ] + ) + ); + + // _loadPackTranslation + $packData = [ + 'pack original' => 'pack translated', + 'module pack' => 'pack translated overwrite', + 'module db' => 'pack-db translated overwrite', + ]; + $this->packDictionary->expects($this->once())->method('getDictionary')->will($this->returnValue($packData)); + + // _loadThemeTranslation() + $this->viewFileSystem->expects($this->any()) + ->method('getLocaleFileName') + ->will($this->returnValue('/theme.csv')); + + // _loadDbTranslation() + $dbData = [ + 'db original' => 'db translated', + 'module db' => 'db translated overwrite', + ]; + $this->resource->expects($this->any())->method('getTranslationArray')->will($this->returnValue($dbData)); + + $this->cache->expects($this->exactly($forceReload ? 0 : 1))->method('save'); + + $this->translate->loadData($area, $forceReload); + + $expected = [ + 'module original' => 'module translated', + 'module theme' => 'theme translated overwrite', + 'module pack' => 'theme-pack translated overwrite', + 'module db' => 'db translated overwrite', + 'theme original' => 'theme translated', + 'pack original' => 'pack translated', + 'db original' => 'db translated', + ]; + $this->assertEquals($expected, $this->translate->getData()); + } + + /** + * @return array + */ + public function dataProviderForTestLoadData() + { + return [ + ['adminhtml', true], + ['adminhtml', false], + ['frontend', true], + ['frontend', false], + [null, true], + [null, false] + ]; + } + + /** + * @param $data + * @param $result + * @dataProvider dataProviderForTestGetData + */ + public function testGetData($data, $result) + { + $this->cache->expects($this->once()) + ->method('load') + ->will($this->returnValue(json_encode($data))); + $this->expectsSetConfig('themeId'); + $this->translate->loadData('frontend'); + $this->assertEquals($result, $this->translate->getData()); + } + + /** + * @return array + */ + public function dataProviderForTestGetData() + { + $data = ['original 1' => 'translated 1', 'original 2' => 'translated 2']; + return [ + [$data, $data], + [null, []] + ]; + } + + public function testGetLocale() + { + $this->locale->expects($this->once())->method('getLocale')->will($this->returnValue('en_US')); + $this->assertEquals('en_US', $this->translate->getLocale()); + + $this->locale->expects($this->never())->method('getLocale'); + $this->assertEquals('en_US', $this->translate->getLocale()); + + $this->locale->expects($this->never())->method('getLocale'); + $this->translate->setLocale('en_GB'); + $this->assertEquals('en_GB', $this->translate->getLocale()); + } + + public function testSetLocale() + { + $this->translate->setLocale('en_GB'); + $this->locale->expects($this->never())->method('getLocale'); + $this->assertEquals('en_GB', $this->translate->getLocale()); + } + + public function testGetTheme() + { + $this->request->expects($this->at(0))->method('getParam')->with('theme')->will($this->returnValue('')); + + $requestTheme = ['theme_title' => 'Theme Title']; + $this->request->expects($this->at(1))->method('getParam')->with('theme') + ->will($this->returnValue($requestTheme)); + + $this->assertEquals('theme', $this->translate->getTheme()); + $this->assertEquals('themeTheme Title', $this->translate->getTheme()); + } + + public function testLoadDataNoTheme() + { + $forceReload = true; + $this->expectsSetConfig(null, null); + $this->moduleList->expects($this->once())->method('getNames')->will($this->returnValue([])); + $this->appState->expects($this->once())->method('getAreaCode')->will($this->returnValue('frontend')); + $this->packDictionary->expects($this->once())->method('getDictionary')->will($this->returnValue([])); + $this->resource->expects($this->any())->method('getTranslationArray')->will($this->returnValue([])); + $this->assertEquals($this->translate, $this->translate->loadData(null, $forceReload)); + } + + /** + * Declare calls expectation for setConfig() method + */ + protected function expectsSetConfig($themeId, $localeCode = 'en_US') + { + $this->locale->expects($this->any())->method('getLocale')->will($this->returnValue($localeCode)); + $scope = new \Magento\Framework\DataObject(['code' => 'frontendCode', 'id' => 1]); + $scopeAdmin = new \Magento\Framework\DataObject(['code' => 'adminCode', 'id' => 0]); + $this->scopeResolver->expects($this->any()) + ->method('getScope') + ->will( + $this->returnValueMap( + [ + [null, $scope], + ['admin', $scopeAdmin], + ] + ) + ); + $designTheme = $this->getMockBuilder(\Magento\Theme\Model\Theme::class) + ->disableOriginalConstructor() + ->getMock(); + + $designTheme->expects($this->once()) + ->method('getThemePath') + ->willReturn($themeId); + + $this->viewDesign->expects($this->any())->method('getDesignTheme')->will($this->returnValue($designTheme)); + } +} diff --git a/lib/internal/Magento/Framework/Translate.php b/lib/internal/Magento/Framework/Translate.php index ff1bf99162a8a..ce73338eee292 100644 --- a/lib/internal/Magento/Framework/Translate.php +++ b/lib/internal/Magento/Framework/Translate.php @@ -398,11 +398,11 @@ protected function _getModuleTranslationFile($moduleName, $locale) /** * Get theme translation locale file name * - * @param string $locale + * @param string|null $locale * @param array $config * @return string|null */ - private function getThemeTranslationFileName(string $locale, array $config): ?string + private function getThemeTranslationFileName(?string $locale, array $config): ?string { $fileName = $this->_viewFileSystem->getLocaleFileName( 'i18n' . '/' . $locale . '.csv', From fe73cf00549475b0ffc5a470e10ba4f1f3893b78 Mon Sep 17 00:00:00 2001 From: Vladyslav Podorozhnyi <v.podorozhnyi@ism-ukraine.com> Date: Sat, 10 Nov 2018 11:57:22 +0200 Subject: [PATCH 0598/1158] =?UTF-8?q?magento/magento2#17833:=C2=A0=20Child?= =?UTF-8?q?=20theme=20does=20not=20inherit=20translations=20from=20parent?= =?UTF-8?q?=20theme=20-=20forward=20port=20unit=20tests=20from=202.2-devel?= =?UTF-8?q?op=20branch=20-=20declare=20strict=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Framework/Test/Unit/TranslateTest.php | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php b/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php index 6a6407c97a95f..885be8557fa10 100644 --- a/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Framework\Test\Unit; use Magento\Framework\Serialize\SerializerInterface; @@ -61,7 +63,7 @@ class TranslateTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Framework\Filesystem\DriverInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $fileDriver; - protected function setUp() + protected function setUp(): void { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->viewDesign = $this->createMock(\Magento\Framework\View\DesignInterface::class); @@ -128,7 +130,7 @@ protected function setUp() * @param array $cachedData * @dataProvider dataProviderLoadDataCachedTranslation */ - public function testLoadDataCachedTranslation($area, $forceReload, $cachedData) + public function testLoadDataCachedTranslation($area, $forceReload, $cachedData): void { $this->expectsSetConfig('Magento/luma'); @@ -147,7 +149,7 @@ public function testLoadDataCachedTranslation($area, $forceReload, $cachedData) /** * @return array */ - public function dataProviderLoadDataCachedTranslation() + public function dataProviderLoadDataCachedTranslation(): array { $cachedData = ['cached 1' => 'translated 1', 'cached 2' => 'translated 2']; return [ @@ -163,7 +165,7 @@ public function dataProviderLoadDataCachedTranslation() * @dataProvider dataProviderForTestLoadData * @SuppressWarnings(PHPMD.NPathComplexity) */ - public function testLoadData($area, $forceReload) + public function testLoadData($area, $forceReload): void { $this->expectsSetConfig('Magento/luma'); @@ -258,7 +260,7 @@ public function testLoadData($area, $forceReload) /** * @return array */ - public function dataProviderForTestLoadData() + public function dataProviderForTestLoadData(): array { return [ ['adminhtml', true], @@ -275,7 +277,7 @@ public function dataProviderForTestLoadData() * @param $result * @dataProvider dataProviderForTestGetData */ - public function testGetData($data, $result) + public function testGetData($data, $result): void { $this->cache->expects($this->once()) ->method('load') @@ -288,7 +290,7 @@ public function testGetData($data, $result) /** * @return array */ - public function dataProviderForTestGetData() + public function dataProviderForTestGetData(): array { $data = ['original 1' => 'translated 1', 'original 2' => 'translated 2']; return [ @@ -297,7 +299,7 @@ public function dataProviderForTestGetData() ]; } - public function testGetLocale() + public function testGetLocale(): void { $this->locale->expects($this->once())->method('getLocale')->will($this->returnValue('en_US')); $this->assertEquals('en_US', $this->translate->getLocale()); @@ -310,14 +312,14 @@ public function testGetLocale() $this->assertEquals('en_GB', $this->translate->getLocale()); } - public function testSetLocale() + public function testSetLocale(): void { $this->translate->setLocale('en_GB'); $this->locale->expects($this->never())->method('getLocale'); $this->assertEquals('en_GB', $this->translate->getLocale()); } - public function testGetTheme() + public function testGetTheme(): void { $this->request->expects($this->at(0))->method('getParam')->with('theme')->will($this->returnValue('')); @@ -329,7 +331,7 @@ public function testGetTheme() $this->assertEquals('themeTheme Title', $this->translate->getTheme()); } - public function testLoadDataNoTheme() + public function testLoadDataNoTheme(): void { $forceReload = true; $this->expectsSetConfig(null, null); @@ -343,7 +345,7 @@ public function testLoadDataNoTheme() /** * Declare calls expectation for setConfig() method */ - protected function expectsSetConfig($themeId, $localeCode = 'en_US') + protected function expectsSetConfig($themeId, $localeCode = 'en_US'): void { $this->locale->expects($this->any())->method('getLocale')->will($this->returnValue($localeCode)); $scope = new \Magento\Framework\DataObject(['code' => 'frontendCode', 'id' => 1]); From 16f2e0dd0b83e2d4135a384d3fb19a9e2db5c32c Mon Sep 17 00:00:00 2001 From: LisovyiEvhenii <lisovyievhenii@gmail.com> Date: Sat, 10 Nov 2018 11:44:19 +0200 Subject: [PATCH 0599/1158] Add availability to leave empty config for events.xml --- lib/internal/Magento/Framework/Event/etc/events.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Event/etc/events.xsd b/lib/internal/Magento/Framework/Event/etc/events.xsd index d656b7fdb6ed6..cac62af356760 100644 --- a/lib/internal/Magento/Framework/Event/etc/events.xsd +++ b/lib/internal/Magento/Framework/Event/etc/events.xsd @@ -9,7 +9,7 @@ <xs:element name="config"> <xs:complexType> <xs:sequence> - <xs:element name="event" type="eventDeclaration" minOccurs="1" maxOccurs="unbounded"> + <xs:element name="event" type="eventDeclaration" minOccurs="0" maxOccurs="unbounded"> <xs:unique name="uniqueObserverName"> <xs:annotation> <xs:documentation> From 2d45eb37e2ee1b40eb59fbb0f60cc66c38198438 Mon Sep 17 00:00:00 2001 From: Max Almonte <maxalmonte14@hotmail.com> Date: Sat, 10 Nov 2018 10:51:04 -0400 Subject: [PATCH 0600/1158] Added _customerCollection property as public --- .../Model/ResourceModel/Import/Customer/Storage.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php index c5d28240c3068..1046afeebbf9b 100644 --- a/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php +++ b/app/code/Magento/CustomerImportExport/Model/ResourceModel/Import/Customer/Storage.php @@ -48,6 +48,11 @@ class Storage */ private $customerCollectionFactory; + /** + * @var CustomerCollection + */ + public $_customerCollection; + /** * @param CustomerCollectionFactory $collectionFactory * @param CollectionByPagesIteratorFactory $colIteratorFactory @@ -58,6 +63,9 @@ public function __construct( CollectionByPagesIteratorFactory $colIteratorFactory, array $data = [] ) { + $this->_customerCollection = isset( + $data['customer_collection'] + ) ? $data['customer_collection'] : $collectionFactory->create(); $this->_pageSize = isset($data['page_size']) ? $data['page_size'] : 0; $this->_byPagesIterator = isset( $data['collection_by_pages_iterator'] From 7f3808cd5821355ec6193ae1d7785f0f522c889d Mon Sep 17 00:00:00 2001 From: Max Almonte <maxalmonte14@hotmail.com> Date: Sat, 10 Nov 2018 11:04:47 -0400 Subject: [PATCH 0601/1158] Added public connection property --- .../Magento/DownloadableImportExport/Helper/Uploader.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php index 5fc4df1d03c49..de10bcea5d61e 100644 --- a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php +++ b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php @@ -38,6 +38,11 @@ class Uploader extends \Magento\Framework\App\Helper\AbstractHelper */ protected $parameters = []; + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface + */ + public $connection; + /** * Construct * @@ -62,6 +67,7 @@ public function __construct( $this->fileUploader->init(); $this->fileUploader->setAllowedExtensions($this->getAllowedExtensions()); $this->fileUploader->removeValidateCallback('catalog_product_image'); + $this->connection = $resource->getConnection('write'); $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); } From 1f1ec545f4a9e6d39dfd1ad186ecf2bafae36496 Mon Sep 17 00:00:00 2001 From: Alexandr Voronoy <servermed@gmail.com> Date: Sat, 10 Nov 2018 20:01:19 +0200 Subject: [PATCH 0602/1158] Cleanup with static test --- app/code/Magento/Backend/Block/Widget/Grid.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/Backend/Block/Widget/Grid.php b/app/code/Magento/Backend/Block/Widget/Grid.php index e9394be9e60bd..66298d23389fb 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid.php +++ b/app/code/Magento/Backend/Block/Widget/Grid.php @@ -150,7 +150,10 @@ public function __construct( } /** + * Internal constructor, that is called from real constructor + * * @return void + * * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function _construct() @@ -709,6 +712,7 @@ public function getGridUrl() /** * Grid url getter + * * Version of getGridUrl() but with parameters * * @param array $params url parameters From ae61da5e5351745664672d17ad77059273d0af00 Mon Sep 17 00:00:00 2001 From: Oleksii Gorbulin <a.gorbulin@ism-ukraine.com> Date: Sat, 10 Nov 2018 20:06:15 +0200 Subject: [PATCH 0603/1158] 19082-Fatal-error-Uncaught-Error-Cannot-call-abstract-method-Magento-Framework-App-ActionInterface-execute add method to prevent fatal error when go to catalog/product/compare/ --- app/code/Magento/Catalog/Controller/Product/Compare.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/code/Magento/Catalog/Controller/Product/Compare.php b/app/code/Magento/Catalog/Controller/Product/Compare.php index 1ee146e5aaa70..63478080bce1a 100644 --- a/app/code/Magento/Catalog/Controller/Product/Compare.php +++ b/app/code/Magento/Catalog/Controller/Product/Compare.php @@ -139,4 +139,13 @@ public function setCustomerId($customerId) $this->_customerId = $customerId; return $this; } + + /** + * {@inheritdoc} + */ + public function execute() + { + return $this->_redirect('catalog/product_compare'); + } + } From 7ae271e7768c713e7ad83e8631e7308ac5b22193 Mon Sep 17 00:00:00 2001 From: LisovyiEvhenii <lisovyievhenii@gmail.com> Date: Sun, 11 Nov 2018 12:17:24 +0200 Subject: [PATCH 0604/1158] Fix unit test of Framework/Event module --- .../Event/Test/Unit/Config/_files/invalidEventsXmlArray.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php index 33007b7295bca..e0dc7494cca19 100644 --- a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php +++ b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php @@ -4,10 +4,6 @@ * See COPYING.txt for license details. */ return [ - 'without_event_handle' => [ - '<?xml version="1.0"?><config></config>', - ["Element 'config': Missing child element(s). Expected is ( event ).\nLine: 1\n"], - ], 'event_without_required_name_attribute' => [ '<?xml version="1.0"?><config><event name="some_name"></event></config>', ["Element 'event': Missing child element(s). Expected is ( observer ).\nLine: 1\n"], From 300772deea6e9f8678dd964807dbb31d327b1ad1 Mon Sep 17 00:00:00 2001 From: Nazar Klovanych <nazarn96@gmail.com> Date: Sun, 11 Nov 2018 22:34:04 +0200 Subject: [PATCH 0605/1158] Fix issue 18941 --- app/code/Magento/Store/Model/Store.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 04e98ed88db23..4282efb6e55e8 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1164,18 +1164,21 @@ public function isDefault() * Retrieve current url for store * * @param bool $fromStore - * @param bool $clearUrl * @return string * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - public function getCurrentUrl($fromStore = true, $clearUrl = false) + public function getCurrentUrl($fromStore = true) { $sidQueryParam = $this->_sidResolver->getSessionIdQueryParam($this->_getSession()); $requestString = $this->_url->escape(ltrim($this->_request->getRequestString(), '/')); $storeUrl = $this->getUrl('', ['_secure' => $this->_storeManager->getStore()->isCurrentlySecure()]); + if ($this->_config->getValue(self::XML_PATH_STORE_IN_URL)) { + $storeUrl = preg_replace('/\/'.$this->getCode().'{1}/','',$storeUrl); + } + if (!filter_var($storeUrl, FILTER_VALIDATE_URL)) { return $storeUrl; } @@ -1218,10 +1221,6 @@ public function getCurrentUrl($fromStore = true, $clearUrl = false) $currentUrlQueryParams = array_merge($requestString, $storeParsedQuery); - if ($clearUrl !== false) { - $currentUrlQueryParams = false; - } - $currentUrl = $storeParsedUrl['scheme'] . '://' . $storeParsedUrl['host'] From ebfffe494247b4f49d2fb127b7823999202c2b7a Mon Sep 17 00:00:00 2001 From: Ravi Chandra <ravi.chandra@krishtechnolabs.com> Date: Mon, 12 Nov 2018 14:33:04 +0530 Subject: [PATCH 0606/1158] Fixed subscribe to newsletter if you already have an account issue #8952 --- .../Magento/Newsletter/Controller/Subscriber/NewAction.php | 5 +++-- .../Magento/Newsletter/Controller/SubscriberTest.php | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php index fd2a61702e909..a9ef89070c659 100644 --- a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php +++ b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php @@ -77,8 +77,9 @@ public function __construct( protected function validateEmailAvailable($email) { $websiteId = $this->_storeManager->getStore()->getWebsiteId(); - if ($this->_customerSession->getCustomerDataObject()->getEmail() !== $email - && !$this->customerAccountManagement->isEmailAvailable($email, $websiteId) + if ($this->_customerSession->isLoggedIn() + && ($this->_customerSession->getCustomerDataObject()->getEmail() !== $email + && !$this->customerAccountManagement->isEmailAvailable($email, $websiteId)) ) { throw new LocalizedException( __('This email address is already assigned to another user.') diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php index 5347881f5e7d4..9dbf5c4d2a2a9 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php @@ -57,7 +57,7 @@ public function testNewActionUsedEmail() $this->dispatch('newsletter/subscriber/new'); $this->assertSessionMessages($this->equalTo([ - 'There was a problem with the subscription: This email address is already assigned to another user.', + 'Thank you for your subscription.', ])); $this->assertRedirect($this->anything()); } From 769e46d47a237f1d06e53c2c52341d45cf610531 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Mon, 12 Nov 2018 13:52:54 +0200 Subject: [PATCH 0607/1158] Improving the current link logic, by covering all the possible cases for default parts --- .../View/Element/Html/Link/Current.php | 21 +++------ .../Unit/Element/Html/Link/CurrentTest.php | 47 ++++++++----------- 2 files changed, 25 insertions(+), 43 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php index cb29c67a2ca30..d5da6cefae5b9 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php @@ -64,14 +64,15 @@ public function getHref() private function getMca() { $routeParts = [ - 'module' => $this->_request->getModuleName(), - 'controller' => $this->_request->getControllerName(), - 'action' => $this->_request->getActionName(), + $this->_request->getModuleName(), + $this->_request->getControllerName(), + $this->_request->getActionName(), ]; $parts = []; + $pathParts = explode('/', $this->getPath()); foreach ($routeParts as $key => $value) { - if (!empty($value) && $value != $this->_defaultPath->getPart($key)) { + if (isset($pathParts[$key]) && $pathParts[$key] === $value) { $parts[] = $value; } } @@ -85,7 +86,7 @@ private function getMca() */ public function isCurrent() { - return $this->getCurrent() || $this->getUrl($this->getPath()) == $this->getUrl($this->getPathInfo()); + return $this->getCurrent() || $this->getUrl($this->getPath()) == $this->getUrl($this->getMca()); } /** @@ -151,14 +152,4 @@ private function getAttributesHtml() return $attributesHtml; } - - /** - * Get current page path info - * - * @return string - */ - private function getPathInfo() - { - return trim($this->_request->getPathInfo(), '/'); - } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php index 9c720f0f48dc3..e11468061c9ec 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/Link/CurrentTest.php @@ -57,26 +57,31 @@ public function testIsCurrentIfIsset() /** * Test if the current url is the same as link path * - * @dataProvider linkPathProvider - * @param string $linkPath - * @param string $currentPathInfo - * @param bool $expected * @return void */ - public function testIsCurrent($linkPath, $currentPathInfo, $expected) + public function testIsCurrent() { - $baseUrl = 'http://example.com/'; - $trimmed = trim($currentPathInfo, '/'); + $path = 'test/index'; + $url = 'http://example.com/test/index'; - $this->_requestMock->expects($this->any())->method('getPathInfo')->willReturn($currentPathInfo); + $this->_requestMock->expects($this->once()) + ->method('getModuleName') + ->will($this->returnValue('test')); + $this->_requestMock->expects($this->once()) + ->method('getControllerName') + ->will($this->returnValue('index')); + $this->_requestMock->expects($this->once()) + ->method('getActionName') + ->will($this->returnValue('index')); $this->_urlBuilderMock->expects($this->at(0)) ->method('getUrl') - ->with($linkPath) - ->will($this->returnValue($baseUrl . $linkPath)); + ->with($path) + ->will($this->returnValue($url)); $this->_urlBuilderMock->expects($this->at(1)) ->method('getUrl') - ->with($trimmed) - ->will($this->returnValue($baseUrl . $trimmed)); + ->with('test/index') + ->will($this->returnValue($url)); + /** @var \Magento\Framework\View\Element\Html\Link\Current $link */ $link = $this->_objectManager->getObject( \Magento\Framework\View\Element\Html\Link\Current::class, @@ -86,22 +91,8 @@ public function testIsCurrent($linkPath, $currentPathInfo, $expected) ] ); - $link->setCurrent(false); - $link->setPath($linkPath); - $this->assertEquals($expected, $link->isCurrent()); - } - - /** - * @return array - */ - public function linkPathProvider() - { - return [ - ['test/index', '/test/index/', true], - ['test/index/index', '/test/index/index/', true], - ['test/route', '/test/index/', false], - ['test/index', '/test/', false] - ]; + $link->setPath($path); + $this->assertTrue($link->isCurrent()); } public function testIsCurrentFalse() From 284daec007cc9cc5bacc736e3d6ce00ebdf751ef Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Mon, 12 Nov 2018 15:00:28 +0200 Subject: [PATCH 0608/1158] magento/magento2#5929: [Forwardport] Saving Product does not update URL rewrite. --- ...ProductProcessUrlRewriteSavingObserver.php | 21 +++++++++++++++++-- ...uctProcessUrlRewriteSavingObserverTest.php | 3 +++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php index c4d67f447e2cf..6eda8dd0b61ee 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php @@ -6,11 +6,15 @@ namespace Magento\CatalogUrlRewrite\Observer; use Magento\Catalog\Model\Product; +use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator; use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; +use Magento\Framework\App\ObjectManager; use Magento\UrlRewrite\Model\UrlPersistInterface; -use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; use Magento\Framework\Event\ObserverInterface; +/** + * Class ProductProcessUrlRewriteSavingObserver + */ class ProductProcessUrlRewriteSavingObserver implements ObserverInterface { /** @@ -23,22 +27,33 @@ class ProductProcessUrlRewriteSavingObserver implements ObserverInterface */ private $urlPersist; + /** + * @var ProductUrlPathGenerator + */ + private $productUrlPathGenerator; + /** * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator * @param UrlPersistInterface $urlPersist + * @param ProductUrlPathGenerator|null $productUrlPathGenerator */ public function __construct( ProductUrlRewriteGenerator $productUrlRewriteGenerator, - UrlPersistInterface $urlPersist + UrlPersistInterface $urlPersist, + ProductUrlPathGenerator $productUrlPathGenerator = null ) { $this->productUrlRewriteGenerator = $productUrlRewriteGenerator; $this->urlPersist = $urlPersist; + $this->productUrlPathGenerator = $productUrlPathGenerator ?: ObjectManager::getInstance() + ->get(ProductUrlPathGenerator::class); } /** * Generate urls for UrlRewrite and save it in storage + * * @param \Magento\Framework\Event\Observer $observer * @return void + * @throws \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException */ public function execute(\Magento\Framework\Event\Observer $observer) { @@ -51,6 +66,8 @@ public function execute(\Magento\Framework\Event\Observer $observer) || $product->dataHasChangedFor('visibility') ) { if ($product->isVisibleInSiteVisibility()) { + $product->unsUrlPath(); + $product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product)); $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product)); } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php index 9de0588356c43..c72a58197b1fd 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php @@ -90,6 +90,7 @@ public function testUrlKeyHasChangedInGlobalContext() $product->setData('save_rewrites_history', true); $product->setUrlKey('new-url'); + $product->setUrlPath('new-path'); $product->save(); $expected = [ @@ -152,6 +153,7 @@ public function testUrlKeyHasChangedInStoreviewContextWithPermanentRedirection() $product->setData('save_rewrites_history', true); $product->setUrlKey('new-url'); + $product->setUrlPath('new-path'); $product->save(); $expected = [ @@ -207,6 +209,7 @@ public function testUrlKeyHasChangedInStoreviewContextWithoutPermanentRedirectio $product->setData('save_rewrites_history', false); $product->setUrlKey('new-url'); + $product->setUrlPath('new-path'); $product->save(); $expected = [ From 479a95f1e3fb58044d23f15e904f221b2e017574 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Mon, 12 Nov 2018 15:01:31 +0200 Subject: [PATCH 0609/1158] MAGETWO-96208: Mass action "Delete" removes all addresses --- .../Controller/Adminhtml/Address/MassDelete.php | 8 +++++++- .../ResourceModel/Address/Grid/Collection.php | 16 ---------------- .../Component/Listing/Address/DataProvider.php | 14 +++++++++++++- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index 09523f9e6a956..10638739f2b0a 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -87,12 +87,18 @@ public function __construct( */ public function execute(): Json { + $customerData = $this->_session->getData('customer_data'); /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ $collection = $this->filter->getCollection($this->collectionFactory->create()); - $collectionSize = $collection->getSize(); $error = false; try { + if ($customerData && $customerData['customer_id']) { + $collection->addFieldToFilter('parent_id', $customerData['customer_id']); + } else { + throw new \Exception(); + } + $collectionSize = $collection->getSize(); /** @var \Magento\Customer\Model\Address $address */ foreach ($collection as $address) { $this->addressRepository->deleteById($address->getId()); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php index 09aef78b6cebc..b0e4c3d8dcc24 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -76,22 +76,6 @@ public function __construct( ); } - /** - * Resource initialization - * - * @return $this - */ - protected function _initSelect() - { - parent::_initSelect(); - $parentId = $this->context->getRequestParam('parent_id'); - if ($parentId !== null) { - $this->getSelect()->where('parent_id=?', $parentId); - } - - return $this; - } - /** * @inheritdoc * diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php index df92e7c1c9421..e034e5a894e96 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php @@ -12,11 +12,17 @@ */ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider { + /** + * @var \Magento\Framework\App\RequestInterface $request, + */ + private $request; + /** * @param string $name * @param string $primaryFieldName * @param string $requestFieldName * @param CollectionFactory $collectionFactory + * @param \Magento\Framework\App\RequestInterface $request * @param array $meta * @param array $data */ @@ -25,11 +31,13 @@ public function __construct( $primaryFieldName, $requestFieldName, CollectionFactory $collectionFactory, + \Magento\Framework\App\RequestInterface $request, array $meta = [], array $data = [] ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); $this->collection = $collectionFactory->create(); + $this->request = $request; } /** @@ -40,7 +48,11 @@ public function __construct( public function getData(): array { $collection = $this->getCollection(); - $data = $collection->toArray(); + $data['items'] = []; + if ($this->request->getParam('parent_id')) { + $collection->addFieldToFilter('parent_id', $this->request->getParam('parent_id')); + $data = $collection->toArray(); + } foreach ($data['items'] as $key => $item) { if (isset($item['country_id']) && !isset($item['country'])) { $data['items'][$key]['country'] = $item['country_id']; From 63922949f0a1a2d018900672968cd8714a901db7 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 12 Nov 2018 15:01:50 +0200 Subject: [PATCH 0610/1158] GraphQl-28: Implement query complexity limiting --- app/code/Magento/GraphQl/etc/di.xml | 2 +- .../Framework/GraphQl/Query/QueryComplexityLimiter.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index 622888f697b84..914dcc78e49e1 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -100,7 +100,7 @@ <type name="Magento\Framework\GraphQl\Query\QueryComplexityLimiter"> <arguments> <argument name="queryDepth" xsi:type="number">20</argument> - <argument name="queryComplexity" xsi:type="number">160</argument> + <argument name="queryComplexity" xsi:type="number">250</argument> </arguments> </type> </config> diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index 3936da21fc56a..5730156ca5b34 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -38,8 +38,8 @@ class QueryComplexityLimiter * @param int $queryComplexity */ public function __construct( - int $queryDepth = 20, - int $queryComplexity = 160 + int $queryDepth, + int $queryComplexity ) { $this->queryDepth = $queryDepth; $this->queryComplexity = $queryComplexity; From 29a86a3907115d0f186d9937a5f90d45626f6566 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Mon, 12 Nov 2018 15:35:16 +0200 Subject: [PATCH 0611/1158] magento/magento2#16887: [Forwardport] Fix blocked a frame with origin. --- .../view/frontend/web/js/page-cache.js | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js b/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js index fccc8510ffc70..11707ea491fb5 100644 --- a/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js +++ b/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js @@ -6,9 +6,10 @@ define([ 'jquery', 'domReady', + 'consoleLogger', 'jquery/ui', 'mage/cookies' -], function ($, domReady) { +], function ($, domReady, consoleLogger) { 'use strict'; /** @@ -46,14 +47,30 @@ define([ // prevent cross origin iframe content reading if ($(element).prop('tagName') === 'IFRAME') { iframeHostName = $('<a>').prop('href', $(element).prop('src')) - .prop('hostname'); + .prop('hostname'); if (window.location.hostname !== iframeHostName) { return []; } } - $(element).contents().each(function (index, el) { + // rewrite jQuery contents() + var contents = function (element) { + return $.map(element, function (elem) { + try { + return $.nodeName(elem, "iframe") ? + elem.contentDocument || (elem.contentWindow ? elem.contentWindow.document : []) : + $.merge([], elem.childNodes); + } catch (e) { + consoleLogger.error(e); + return []; + } + }); + }; + + var elementContents = contents($(element)); + + $.each(elementContents, function (index, el) { switch (el.nodeType) { case 1: // ELEMENT_NODE lookup(el); From f0dedde4c6fa32c84579928d48d613cf65684eca Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 12 Nov 2018 15:59:02 +0200 Subject: [PATCH 0612/1158] GraphQl-41: [Query] My Account > My Orders --- .../SalesGraphQl/Model/Resolver/Orders.php | 98 ++++++------ app/code/Magento/SalesGraphQl/composer.json | 3 + .../Magento/GraphQl/Sales/OrdersTest.php | 133 ++++++++-------- .../Sales/_files/orders_with_customer.php | 148 +++++++++--------- 4 files changed, 188 insertions(+), 194 deletions(-) diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php index 05af6829de454..f058ce9ae3bdd 100644 --- a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php +++ b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php @@ -7,70 +7,66 @@ namespace Magento\SalesGraphQl\Model\Resolver; -use Magento\Authorization\Model\UserContextInterface; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface; -use Magento\CustomerGraphQl\Model\Customer\CheckCustomerAccountInterface; +use Magento\CustomerGraphQl\Model\Customer\CheckCustomerAccount; /** - * Class Orders + * Orders data reslover */ class Orders implements ResolverInterface { - /** - * @var CollectionFactoryInterface - */ - private $collectionFactory; + /** + * @var CollectionFactoryInterface + */ + private $collectionFactory; - /** - * @var CheckCustomerAccountInterface - */ - private $checkCustomerAccount; + /** + * @var CheckCustomerAccount + */ + private $checkCustomerAccount; - /** - * Orders constructor. - * @param CollectionFactoryInterface $collectionFactory - * @param CheckCustomerAccountInterface $checkCustomerAccount - */ - public function __construct( - CollectionFactoryInterface $collectionFactory, - CheckCustomerAccountInterface $checkCustomerAccount - ) { - $this->collectionFactory = $collectionFactory; - $this->checkCustomerAccount = $checkCustomerAccount; + /** + * @param CollectionFactoryInterface $collectionFactory + * @param CheckCustomerAccount $checkCustomerAccount + */ + public function __construct( + CollectionFactoryInterface $collectionFactory, + CheckCustomerAccount $checkCustomerAccount + ) { + $this->collectionFactory = $collectionFactory; + $this->checkCustomerAccount = $checkCustomerAccount; - } + } - /** - * {@inheritdoc} - */ - public function resolve( - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - $customerId = $context->getUserId(); + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + $customerId = $context->getUserId(); + $this->checkCustomerAccount->execute($customerId, $context->getUserType()); - $this->checkCustomerAccount->execute($customerId, $context->getUserType()); + $items = []; + $orders = $this->collectionFactory->create($customerId); - $items = []; - $orders = $this->collectionFactory->create($customerId); - - /** @var \Magento\Sales\Model\Order $order */ - foreach ($orders as $order) { - $items[] = [ - 'id' => $order->getId(), - 'increment_id' => $order->getIncrementId(), - 'created_at' => $order->getCreatedAt(), - 'grand_total' => $order->getGrandTotal(), - 'status' => $order->getStatus() - ]; - } - - return ['items' => $items]; - } + /** @var \Magento\Sales\Model\Order $order */ + foreach ($orders as $order) { + $items[] = [ + 'id' => $order->getId(), + 'increment_id' => $order->getIncrementId(), + 'created_at' => $order->getCreatedAt(), + 'grand_total' => $order->getGrandTotal(), + 'status' => $order->getStatus(), + ]; + } + return ['items' => $items]; + } } diff --git a/app/code/Magento/SalesGraphQl/composer.json b/app/code/Magento/SalesGraphQl/composer.json index b75e18c7b7a97..3e29adbe7009e 100644 --- a/app/code/Magento/SalesGraphQl/composer.json +++ b/app/code/Magento/SalesGraphQl/composer.json @@ -5,8 +5,11 @@ "require": { "php": "~7.1.3||~7.2.0", "magento/framework": "*", + "magento/module-authorization": "*", "magento/module-customer": "*", + "magento/module-customer-graph-ql": "*", "magento/module-catalog": "*", + "magento/module-sales": "*", "magento/module-store": "*" }, "suggest": { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php index 33620f6e55386..589b0bc7746f8 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrdersTest.php @@ -16,93 +16,88 @@ */ class OrdersTest extends GraphQlAbstract { - /** - * @var CustomerTokenServiceInterface - */ - private $customerTokenService; + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; - /** - * {@inheritdoc} - */ protected function setUp() { parent::setUp(); - $objectManager = Bootstrap::getObjectManager(); - $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + $this->customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class); } - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * @magentoApiDataFixture Magento/Sales/_files/orders_with_customer.php - */ + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Sales/_files/orders_with_customer.php + */ public function testOrdersQuery() { - $query = - <<<QUERY + $query = + <<<QUERY query { customerOrders { items { - id - increment_id - created_at - grand_total - status - } + id + increment_id + created_at + grand_total + status + } } } QUERY; - $currentEmail = 'customer@example.com'; - $currentPassword = 'password'; - - $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword)); + $currentEmail = 'customer@example.com'; + $currentPassword = 'password'; + $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword)); - $expectedData = [ - [ - 'increment_id' => '100000002', - 'status' => 'processing', - 'grand_total' => 120.00 - ], - [ - 'increment_id' => '100000003', - 'status' => 'processing', - 'grand_total' => 130.00 - ], - [ - 'increment_id' => '100000004', - 'status' => 'closed', - 'grand_total' => 140.00 - ], - [ - 'increment_id' => '100000005', - 'status' => 'complete', - 'grand_total' => 150.00 - ], - [ - 'increment_id' => '100000006', - 'status' => 'complete', - 'grand_total' => 160.00 - ] - ]; + $expectedData = [ + [ + 'increment_id' => '100000002', + 'status' => 'processing', + 'grand_total' => 120.00 + ], + [ + 'increment_id' => '100000003', + 'status' => 'processing', + 'grand_total' => 130.00 + ], + [ + 'increment_id' => '100000004', + 'status' => 'closed', + 'grand_total' => 140.00 + ], + [ + 'increment_id' => '100000005', + 'status' => 'complete', + 'grand_total' => 150.00 + ], + [ + 'increment_id' => '100000006', + 'status' => 'complete', + 'grand_total' => 160.00 + ] + ]; - $actualData = $response['customerOrders']['items']; + $actualData = $response['customerOrders']['items']; - foreach ($expectedData as $key => $data) { - $this->assertEquals($data['increment_id'], $actualData[$key]['increment_id']); - $this->assertEquals($data['grand_total'], $actualData[$key]['grand_total']); - $this->assertEquals($data['status'], $actualData[$key]['status']); - } + foreach ($expectedData as $key => $data) { + $this->assertEquals($data['increment_id'], $actualData[$key]['increment_id']); + $this->assertEquals($data['grand_total'], $actualData[$key]['grand_total']); + $this->assertEquals($data['status'], $actualData[$key]['status']); + } } - /** - * @param string $email - * @param string $password - * @return array - * @throws \Magento\Framework\Exception\AuthenticationException - */ - private function getCustomerAuthHeaders(string $email, string $password): array - { - $customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password); - return ['Authorization' => 'Bearer ' . $customerToken]; - } + /** + * @param string $email + * @param string $password + * @return array + * @throws \Magento\Framework\Exception\AuthenticationException + */ + private function getCustomerAuthHeaders(string $email, string $password): array + { + $customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password); + return ['Authorization' => 'Bearer ' . $customerToken]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php index e649396391ca9..6906166f7cbe5 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php @@ -14,88 +14,88 @@ /** @var Order\Item $orderItem */ /** @var array $addressData Data for creating addresses for the orders. */ $orders = [ - [ - 'increment_id' => '100000002', - 'state' => \Magento\Sales\Model\Order::STATE_NEW, - 'status' => 'processing', - 'grand_total' => 120.00, - 'subtotal' => 120.00, - 'base_grand_total' => 120.00, - 'store_id' => 1, - 'website_id' => 1, - 'payment' => $payment - ], - [ - 'increment_id' => '100000003', - 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, - 'status' => 'processing', - 'grand_total' => 130.00, - 'base_grand_total' => 130.00, - 'subtotal' => 130.00, - 'store_id' => 0, - 'website_id' => 0, - 'payment' => $payment - ], - [ - 'increment_id' => '100000004', - 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, - 'status' => 'closed', - 'grand_total' => 140.00, - 'base_grand_total' => 140.00, - 'subtotal' => 140.00, - 'store_id' => 1, - 'website_id' => 1, - 'payment' => $payment - ], - [ - 'increment_id' => '100000005', - 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, - 'status' => 'complete', - 'grand_total' => 150.00, - 'base_grand_total' => 150.00, - 'subtotal' => 150.00, - 'store_id' => 1, - 'website_id' => 1, - 'payment' => $payment - ], - [ - 'increment_id' => '100000006', - 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, - 'status' => 'complete', - 'grand_total' => 160.00, - 'base_grand_total' => 160.00, - 'subtotal' => 160.00, - 'store_id' => 1, - 'website_id' => 1, - 'payment' => $payment - ], + [ + 'increment_id' => '100000002', + 'state' => \Magento\Sales\Model\Order::STATE_NEW, + 'status' => 'processing', + 'grand_total' => 120.00, + 'subtotal' => 120.00, + 'base_grand_total' => 120.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], + [ + 'increment_id' => '100000003', + 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, + 'status' => 'processing', + 'grand_total' => 130.00, + 'base_grand_total' => 130.00, + 'subtotal' => 130.00, + 'store_id' => 0, + 'website_id' => 0, + 'payment' => $payment + ], + [ + 'increment_id' => '100000004', + 'state' => \Magento\Sales\Model\Order::STATE_PROCESSING, + 'status' => 'closed', + 'grand_total' => 140.00, + 'base_grand_total' => 140.00, + 'subtotal' => 140.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], + [ + 'increment_id' => '100000005', + 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, + 'status' => 'complete', + 'grand_total' => 150.00, + 'base_grand_total' => 150.00, + 'subtotal' => 150.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], + [ + 'increment_id' => '100000006', + 'state' => \Magento\Sales\Model\Order::STATE_COMPLETE, + 'status' => 'complete', + 'grand_total' => 160.00, + 'base_grand_total' => 160.00, + 'subtotal' => 160.00, + 'store_id' => 1, + 'website_id' => 1, + 'payment' => $payment + ], ]; /** @var OrderRepositoryInterface $orderRepository */ $orderRepository = $objectManager->create(OrderRepositoryInterface::class); /** @var array $orderData */ foreach ($orders as $orderData) { - /** @var $order \Magento\Sales\Model\Order */ - $order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Sales\Model\Order::class - ); + /** @var $order \Magento\Sales\Model\Order */ + $order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Sales\Model\Order::class + ); - // Reset addresses - /** @var Order\Address $billingAddress */ - $billingAddress = $objectManager->create(OrderAddress::class, ['data' => $addressData]); - $billingAddress->setAddressType('billing'); + // Reset addresses + /** @var Order\Address $billingAddress */ + $billingAddress = $objectManager->create(OrderAddress::class, ['data' => $addressData]); + $billingAddress->setAddressType('billing'); - $shippingAddress = clone $billingAddress; - $shippingAddress->setId(null)->setAddressType('shipping'); + $shippingAddress = clone $billingAddress; + $shippingAddress->setId(null)->setAddressType('shipping'); - $order - ->setData($orderData) - ->addItem($orderItem) - ->setCustomerIsGuest(false) - ->setCustomerId(1) - ->setCustomerEmail('customer@example.com') - ->setBillingAddress($billingAddress) - ->setShippingAddress($shippingAddress); + $order + ->setData($orderData) + ->addItem($orderItem) + ->setCustomerIsGuest(false) + ->setCustomerId(1) + ->setCustomerEmail('customer@example.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress); - $orderRepository->save($order); + $orderRepository->save($order); } From 198fc61326ad0c575997649e649753d946ac3b70 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 12 Nov 2018 16:08:57 +0200 Subject: [PATCH 0613/1158] GraphQl-41: [Query] My Account > My Orders --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index d4ac4fc091bbc..7fc23572cbb34 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "78153b5c8150c0d145b3372a534a45eb", + "content-hash": "7986e75e7ec3308bfd361f2076544eb7", "packages": [ { "name": "braintree/braintree_php", From a04317746efcaa2aa00c04930a5de428e2753ac1 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 12 Nov 2018 16:11:11 +0200 Subject: [PATCH 0614/1158] GraphQl-41: [Query] My Account > My Orders --- app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php index f058ce9ae3bdd..5802115d44b5e 100644 --- a/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php +++ b/app/code/Magento/SalesGraphQl/Model/Resolver/Orders.php @@ -38,7 +38,6 @@ public function __construct( ) { $this->collectionFactory = $collectionFactory; $this->checkCustomerAccount = $checkCustomerAccount; - } /** From 34af04fc6f288e217129ed32a82a60a51bdce5b9 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Mon, 12 Nov 2018 17:11:25 +0300 Subject: [PATCH 0615/1158] MAGETWO-91784: On Payment screen up and down arrow key allow to add -ve numbers - Fixed static test. --- .../view/base/web/js/model/credit-card-validation/validator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js index f9af514a6d4da..c41be40cba144 100644 --- a/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js +++ b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js @@ -23,7 +23,7 @@ }(function ($, cvvValidator, creditCardNumberValidator, yearValidator, monthValidator, creditCardData) { 'use strict'; - $('.payment-method-content input[type="number"]').on('keyup', function() { + $('.payment-method-content input[type="number"]').on('keyup', function () { if ($(this).val() < 0) { $(this).val($(this).val().replace(/^-/, '')); } From 7e5be32f56ac80bde8dbd6d8e55da12c3923dbb4 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Mon, 12 Nov 2018 17:18:10 +0300 Subject: [PATCH 0616/1158] MAGETWO-62728: My Wishlist - quantity input box issue - Fixed static test. --- .../Wishlist/view/frontend/templates/item/column/cart.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml index c1cccae85971c..7578774fabc2c 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml @@ -22,7 +22,7 @@ $allowedQty = $block->getMinMaxQty(); <div class="field qty"> <label class="label" for="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]"><span><?= $block->escapeHtml(__('Qty')) ?></span></label> <div class="control"> - <input type="number" data-role="qty" id="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" class="input-text qty" data-validate="{'required-number':true,'validate-greater-than-zero':true, 'validate-item-quantity':{'minAllowed':<?= $allowedQty['minAllowed'] ?>,'maxAllowed':<?= $allowedQty['maxAllowed'] ?>}}" + <input type="number" data-role="qty" id="qty[<?= /* @noEscape */ $block->escapeHtmlAttr($item->getId()) ?>]" class="input-text qty" data-validate="{'required-number':true,'validate-greater-than-zero':true, 'validate-item-quantity':{'minAllowed':<?= $allowedQty['minAllowed'] ?>,'maxAllowed':<?= $allowedQty['maxAllowed'] ?>}}" name="qty[<?= $block->escapeHtmlAttr($item->getId()) ?>]" value="<?= /* @noEscape */ (int)($block->getAddToCartQty($item) * 1) ?>"> </div> </div> From abc43aca2b420e0b4baebab6c414e2f20a63a3c1 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 12 Nov 2018 16:49:40 +0200 Subject: [PATCH 0617/1158] GraphQl-41: [Query] My Account > My Orders --- app/code/Magento/SalesGraphQl/composer.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/SalesGraphQl/composer.json b/app/code/Magento/SalesGraphQl/composer.json index 3e29adbe7009e..0549d31d59a24 100644 --- a/app/code/Magento/SalesGraphQl/composer.json +++ b/app/code/Magento/SalesGraphQl/composer.json @@ -5,12 +5,8 @@ "require": { "php": "~7.1.3||~7.2.0", "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-customer": "*", "magento/module-customer-graph-ql": "*", - "magento/module-catalog": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/module-sales": "*" }, "suggest": { "magento/module-graph-ql": "*" From 0aad3fb3eeea271eed53f923d0464147666135a5 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 12 Nov 2018 17:02:06 +0200 Subject: [PATCH 0618/1158] GraphQl-41: [Query] My Account > My Orders --- .../testsuite/Magento/Sales/_files/orders_with_customer.php | 1 + .../Magento/Sales/_files/orders_with_customer_rollback.php | 1 + 2 files changed, 2 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php index 6906166f7cbe5..753adb1f38596 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); use Magento\Sales\Model\Order; use Magento\Sales\Api\OrderRepositoryInterface; diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php index 6e24cee501f51..1fb4b4636ab29 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/orders_with_customer_rollback.php @@ -3,5 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); require 'default_rollback.php'; From 0566957554fa964f79518b7b93920fe12db39c8a Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Mon, 12 Nov 2018 17:03:30 +0200 Subject: [PATCH 0619/1158] magento/magento2#18939: [Forwardport] fixed js translation. --- app/code/Magento/Tax/i18n/en_US.csv | 1 + .../Tax/view/frontend/web/js/view/checkout/summary/tax.js | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Tax/i18n/en_US.csv b/app/code/Magento/Tax/i18n/en_US.csv index e6d89deb7696c..836221e2ec974 100644 --- a/app/code/Magento/Tax/i18n/en_US.csv +++ b/app/code/Magento/Tax/i18n/en_US.csv @@ -178,3 +178,4 @@ Rate,Rate "Your credit card will be charged for","Your credit card will be charged for" "An error occurred while loading tax rates.","An error occurred while loading tax rates." "You will be charged for","You will be charged for" +"Not yet calculated", "Not yet calculated" diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js index c86c3b4d1ab06..b21be98531ba9 100644 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js @@ -11,8 +11,9 @@ define([ 'ko', 'Magento_Checkout/js/view/summary/abstract-total', 'Magento_Checkout/js/model/quote', - 'Magento_Checkout/js/model/totals' -], function (ko, Component, quote, totals) { + 'Magento_Checkout/js/model/totals', + 'mage/translate' +], function (ko, Component, quote, totals, $t) { 'use strict'; var isTaxDisplayedInGrandTotal = window.checkoutConfig.includeTaxInGrandTotal, @@ -22,7 +23,7 @@ define([ return Component.extend({ defaults: { isTaxDisplayedInGrandTotal: isTaxDisplayedInGrandTotal, - notCalculatedMessage: 'Not yet calculated', + notCalculatedMessage: $t('Not yet calculated'), template: 'Magento_Tax/checkout/summary/tax' }, totals: quote.getTotals(), From daf7bcbefd8bddeab0043229883700f04de59f65 Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Mon, 12 Nov 2018 18:08:28 +0200 Subject: [PATCH 0620/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - delete several waits, add minor changes according to code review comments --- ...rderWithOnlinePaymentIncludingTaxAndDiscount.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml index 7c0a503e7bb4b..4feb47ae78e15 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml @@ -10,20 +10,20 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="CreateAdminOrderPayedWithOnlinePaymentIncludingTaxAndDiscount"> <annotations> - <features value="Sales"/> + <features value="Braintree"/> <stories value="Get access to a New Credit Memo Page from Invocie for Order payed with online payment via Admin"/> <title value="Admin should be able to open a New Credit Memo Page from Invoice Page for Order with tax and discount and payed using online payment method"/> <description value="Admin should be able to open a New Credit Memo Page from Invoice Page for Order with tax and discount and payed using online payment method"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-94472"/> - <group value="sales"/> + <group value="braintree"/> </annotations> <before> <!--Create Default Category--> <createData entity="SimpleSubCategory" stepKey="createCategory"/> - <!--Create Simple product with Special Price--> + <!--Create Simple product--> <createData entity="_defaultProduct" stepKey="simpleProduct"> <requiredEntity createDataKey="createCategory"/> </createData> @@ -99,8 +99,9 @@ <!--Submit Order--> <click stepKey="submitOrder" selector="{{NewOrderSection.submitOrder}}"/> - <waitForPageLoad stepKey="waitForSaveConfig" time="10"/> - <waitForElementVisible selector="{{NewOrderSection.successMessage}}" stepKey="waitForSuccessMessage" time="5"/> + <waitForPageLoad stepKey="waitForSubmitOrder" time="5"/> + <see selector="{{NewOrderSection.successMessage}}" userInput="You created the order." stepKey="seeNewOrder" after="waitForSubmitOrder"/> + <!-- Create New invoice--> <actionGroup ref="adminFastCreateInvoice" stepKey="createInvoice"/> @@ -108,6 +109,6 @@ <!--Get access to Credit Memo page from Invocie page--> <click selector="{{AdminInvoiceMainActionsSection.openNewCreditMemoFromInvoice}}" stepKey="clickCreateNewCreditMemo"/> <waitForPageLoad stepKey="waitForLoadNewCreditMemoPage" time="5"/> - <waitForElementVisible selector="{{AdminCreditMemoOrderInformationSection.orderId}}" stepKey="waitForOrderIdOnCreditMemoPage"/> + <see selector="{{AdminCreditMemoOrderInformationSection.orderId}}" userInput="New Memo" stepKey="seeNewCreditMemo" after="waitForLoadNewCreditMemoPage"/> </test> </tests> \ No newline at end of file From 84a3cd8f9c7aa58fccf8f71e527e26295529268a Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Mon, 12 Nov 2018 18:55:56 +0200 Subject: [PATCH 0621/1158] Covering the CheckUserLoginBackendObserver by Unit Test --- .../CheckUserLoginBackendObserverTest.php | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php new file mode 100644 index 0000000000000..b7b11a56fd5ce --- /dev/null +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php @@ -0,0 +1,174 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Captcha\Test\Unit\Observer; + +use Magento\Captcha\Helper\Data; +use Magento\Captcha\Model\DefaultModel; +use Magento\Captcha\Observer\CaptchaStringResolver; +use Magento\Captcha\Observer\CheckUserLoginBackendObserver; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Event; +use Magento\Framework\Event\Observer; +use Magento\Framework\Exception\Plugin\AuthenticationException; +use Magento\Framework\Message\ManagerInterface; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +/** + * Class CheckUserLoginBackendObserverTest + */ +class CheckUserLoginBackendObserverTest extends TestCase +{ + /** + * @var CheckUserLoginBackendObserver + */ + private $observer; + + /** + * @var ManagerInterface|MockObject + */ + private $messageManagerMock; + + /** + * @var CaptchaStringResolver|MockObject + */ + private $captchaStringResolverMock; + + /** + * @var RequestInterface|MockObject + */ + private $requestMock; + + /** + * @var Data|MockObject + */ + private $helperMock; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->helperMock = $this->createMock(Data::class); + $this->messageManagerMock = $this->createMock(ManagerInterface::class); + $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class); + $this->requestMock = $this->createMock(RequestInterface::class); + + $this->observer = new CheckUserLoginBackendObserver( + $this->helperMock, + $this->captchaStringResolverMock, + $this->requestMock + ); + } + + /** + * Test check user login in backend with correct captcha + * + * @dataProvider captchaCorrectnessCheckDataProvider + * @param bool $isRequired + * @param bool $isCorrect + * @param int $invokedTimes + * @return void + * @throws AuthenticationException + */ + public function testCheckOnBackendLoginWithCorrectCaptcha($isRequired, $isCorrect, $invokedTimes) + { + $formId = 'backend_login'; + $login = 'admin'; + $captchaValue = 'captcha-value'; + + $observerMock = $this->createPartialMock(Observer::class, ['getEvent']); + $eventMock = $this->createPartialMock(Event::class, ['getUsername']); + $captcha = $this->createMock(DefaultModel::class); + + $eventMock->expects($this->any()) + ->method('getUsername') + ->willReturn('admin'); + $observerMock->expects($this->any()) + ->method('getEvent') + ->willReturn($eventMock); + $captcha->expects($this->once())->method('isRequired') + ->with($login) + ->willReturn($isRequired); + $captcha->expects($this->exactly($invokedTimes)) + ->method('isCorrect') + ->with($captchaValue) + ->willReturn($isCorrect); + $this->helperMock->expects($this->once()) + ->method('getCaptcha') + ->with($formId) + ->willReturn($captcha); + + $this->captchaStringResolverMock->expects($this->exactly($invokedTimes)) + ->method('resolve') + ->with($this->requestMock, $formId) + ->willReturn($captchaValue); + + $this->messageManagerMock->expects($this->exactly(0)) + ->method('addError') + ->with(__('Incorrect CAPTCHA')); + + $this->observer->execute($observerMock); + } + + /** + * @return array + */ + public function captchaCorrectnessCheckDataProvider() + { + return [ + [true, true, 1], + [false, true, 0] + ]; + } + + + /** + * Test check user login in backend with wrong captcha + * + * @return void + * @throws AuthenticationException + */ + public function testCheckOnBackendLoginWithWrongCaptcha() + { + $formId = 'backend_login'; + $login = 'admin'; + $captchaValue = 'captcha-value'; + + $observerMock = $this->createPartialMock(Observer::class, ['getEvent']); + $eventMock = $this->createPartialMock(Event::class, ['getUsername']); + $captcha = $this->createMock(DefaultModel::class); + + $eventMock->expects($this->any()) + ->method('getUsername') + ->willReturn('admin'); + $observerMock->expects($this->any()) + ->method('getEvent') + ->willReturn($eventMock); + $captcha->expects($this->once())->method('isRequired') + ->with($login) + ->willReturn(true); + $captcha->expects($this->exactly(1)) + ->method('isCorrect') + ->with($captchaValue) + ->willReturn(false); + $this->helperMock->expects($this->once()) + ->method('getCaptcha') + ->with($formId) + ->willReturn($captcha); + + $this->captchaStringResolverMock->expects($this->exactly(1)) + ->method('resolve') + ->with($this->requestMock, $formId) + ->willReturn($captchaValue); + + $this->expectException(AuthenticationException::class, 'Incorrect CAPTCHA.'); + + $this->observer->execute($observerMock); + } +} From 246eb673397e7358bc1ee295bec59ef66b6cfba2 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Mon, 12 Nov 2018 19:02:12 +0200 Subject: [PATCH 0622/1158] Adding strict types --- .../Observer/CheckUserLoginBackendObserverTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php index b7b11a56fd5ce..02f6bed520acd 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Captcha\Test\Unit\Observer; use Magento\Captcha\Helper\Data; @@ -76,12 +78,13 @@ protected function setUp() * @return void * @throws AuthenticationException */ - public function testCheckOnBackendLoginWithCorrectCaptcha($isRequired, $isCorrect, $invokedTimes) + public function testCheckOnBackendLoginWithCorrectCaptcha(bool $isRequired, bool $isCorrect, int $invokedTimes): void { $formId = 'backend_login'; $login = 'admin'; $captchaValue = 'captcha-value'; + /** @var Observer|MockObject $observerMock */ $observerMock = $this->createPartialMock(Observer::class, ['getEvent']); $eventMock = $this->createPartialMock(Event::class, ['getUsername']); $captcha = $this->createMock(DefaultModel::class); @@ -119,7 +122,7 @@ public function testCheckOnBackendLoginWithCorrectCaptcha($isRequired, $isCorrec /** * @return array */ - public function captchaCorrectnessCheckDataProvider() + public function captchaCorrectnessCheckDataProvider(): array { return [ [true, true, 1], @@ -134,12 +137,13 @@ public function captchaCorrectnessCheckDataProvider() * @return void * @throws AuthenticationException */ - public function testCheckOnBackendLoginWithWrongCaptcha() + public function testCheckOnBackendLoginWithWrongCaptcha(): void { $formId = 'backend_login'; $login = 'admin'; $captchaValue = 'captcha-value'; + /** @var Observer|MockObject $observerMock */ $observerMock = $this->createPartialMock(Observer::class, ['getEvent']); $eventMock = $this->createPartialMock(Event::class, ['getUsername']); $captcha = $this->createMock(DefaultModel::class); @@ -167,7 +171,7 @@ public function testCheckOnBackendLoginWithWrongCaptcha() ->with($this->requestMock, $formId) ->willReturn($captchaValue); - $this->expectException(AuthenticationException::class, 'Incorrect CAPTCHA.'); + $this->expectException(AuthenticationException::class); $this->observer->execute($observerMock); } From 548ca3c97565e99ebe8bcfa42e1f421de23c4898 Mon Sep 17 00:00:00 2001 From: Alexandr Voronoy <servermed@gmail.com> Date: Mon, 12 Nov 2018 19:11:54 +0200 Subject: [PATCH 0623/1158] Added option_id in response for product with customizable options. --- app/code/Magento/CatalogGraphQl/etc/schema.graphqls | 1 + .../testsuite/Magento/GraphQl/Catalog/ProductViewTest.php | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 5efe37d8f91f6..5c15d1f4a07e7 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -358,6 +358,7 @@ interface CustomizableOptionInterface @typeResolver(class: "Magento\\CatalogGrap title: String @doc(description: "The display name for this option") required: Boolean @doc(description: "Indicates whether the option is required") sort_order: Int @doc(description: "The order in which the option is displayed") + option_id: Int @doc(description: "Option ID") } interface CustomizableProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\ProductInterfaceTypeResolverComposite") @doc(description: "CustomizableProductInterface contains information about customizable product options.") { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php index 791696b2fa29e..77384165db97f 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductViewTest.php @@ -91,6 +91,7 @@ public function testQueryAllFieldsSimpleProduct() title required sort_order + option_id ... on CustomizableFieldOption { product_sku field_option: value { @@ -337,6 +338,7 @@ public function testQueryMediaGalleryEntryFieldsSimpleProduct() title required sort_order + option_id ... on CustomizableFieldOption { product_sku field_option: value { @@ -753,7 +755,8 @@ private function assertOptions($product, $actualResponse) $assertionMap = [ ['response_field' => 'sort_order', 'expected_value' => $option->getSortOrder()], ['response_field' => 'title', 'expected_value' => $option->getTitle()], - ['response_field' => 'required', 'expected_value' => $option->getIsRequire()] + ['response_field' => 'required', 'expected_value' => $option->getIsRequire()], + ['response_field' => 'option_id', 'expected_value' => $option->getOptionId()] ]; if (!empty($option->getValues())) { @@ -777,7 +780,7 @@ private function assertOptions($product, $actualResponse) ['response_field' => 'product_sku', 'expected_value' => $option->getProductSku()], ] ); - $valueKeyName = ""; + if ($option->getType() === 'file') { $valueKeyName = 'file_option'; $valueAssertionMap = [ From 36bc920210d45be31dbd724e3cff1675feae8b63 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Mon, 12 Nov 2018 19:32:01 +0200 Subject: [PATCH 0624/1158] MAGETWO-96182: Adopt integration and API tests for implemented changes --- .../ui_component/customer_address_listing.xml | 26 ++++---- .../Controller/Adminhtml/Address/SaveTest.php | 60 +------------------ 2 files changed, 13 insertions(+), 73 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 4db5a7fb8d545..b138a81e395a3 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -63,22 +63,20 @@ </settings> </filters> <massaction name="listing_massaction" component="Magento_Customer/js/grid/massactions"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="actions" xsi:type="array"> - <item name="0" xsi:type="array"> - <item name="isAjax" xsi:type="boolean">true</item> - <item name="confirm" xsi:type="array"> - <item name="message" xsi:type="string" translate="true">Are you sure to delete selected address?</item> - <item name="title" xsi:type="string" translate="true">Delete items</item> - </item> - <item name="url" xsi:type="url" path="customer/address/massDelete"/> - <item name="type" xsi:type="string">delete</item> - <item name="label" xsi:type="string" translate="true">Delete</item> + <settings> + <actions xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="isAjax" xsi:type="boolean">true</item> + <item name="confirm" xsi:type="array"> + <item name="message" xsi:type="string" translate="true">Are you sure to delete selected address?</item> + <item name="title" xsi:type="string" translate="true">Delete items</item> </item> + <item name="url" xsi:type="url" path="customer/address/massDelete"/> + <item name="type" xsi:type="string">delete</item> + <item name="label" xsi:type="string" translate="true">Delete</item> </item> - </item> - </argument> + </actions> + </settings> </massaction> <paging name="listing_paging"/> </listingToolbar> diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php index 5a4a426b58cda..cbfa794f94dc0 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -89,19 +89,9 @@ public function testSaveActionWithValidAddressData() $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); - /** - * Check that customer data were cleaned after it was saved successfully - */ + /** Check that customer data were cleaned after it was saved successfully*/ $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - $customer = $this->customerRepository->getById($customerId); $this->assertEquals('Firstname', $customer->getFirstname()); @@ -148,14 +138,6 @@ public function testSaveActionWithDefaultShippingAndBilling() */ $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - /** * Remove stored customer from registry */ @@ -204,50 +186,10 @@ public function testSaveActionWithExistingAdresses() */ $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - $customer = $this->customerRepository->getById($customerId); $this->assertEquals('test firstname', $customer->getFirstname()); $addresses = $customer->getAddresses(); $this->assertCount(4, $addresses); } - - /** - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoDataFixture Magento/Customer/_files/customer_address.php - */ - public function testValidateCustomerWithAddressFailure() - { - $customer = $this->customerRepository->get('customer@example.com'); - $customerId = $customer->getId(); - $post = [ - 'parent_id' => $customerId, - 'firstname' => '', - 'lastname' => '', - 'street' => ['update street'], - 'city' => 'update city', - 'postcode' => '01001', - 'telephone' => '', - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - - $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); - - $this->customerAddress->execute(); - - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages( - $this->equalTo(['One or more input exceptions have occurred.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - } } From 329f4194904dc0da6be8958278f5c9ebad2b54d5 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Mon, 12 Nov 2018 13:23:06 -0600 Subject: [PATCH 0625/1158] MAGETWO-96178: Customer addresses should be saved using Ajax --- .../Listing/Address/DataProvider.php | 10 +++++- .../ui_component/customer_address_form.xml | 4 +-- .../web/js/form/components/insert-listing.js | 36 +++++++++---------- .../adminhtml/web/js/form/element/country.js | 27 ++++++++++++++ .../adminhtml/web/js/form/element/region.js | 27 ++++++++++++++ .../view/adminhtml/web/js/grid/massactions.js | 3 +- .../web/template/default-address.html | 4 +-- 7 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php index e034e5a894e96..75f9dca9fd6cf 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php @@ -17,12 +17,18 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $request; + /** + * @var \Magento\Directory\Model\CountryFactory + */ + private $countryDirectory; + /** * @param string $name * @param string $primaryFieldName * @param string $requestFieldName * @param CollectionFactory $collectionFactory * @param \Magento\Framework\App\RequestInterface $request + * @param \Magento\Directory\Model\CountryFactory $countryFactory, * @param array $meta * @param array $data */ @@ -32,11 +38,13 @@ public function __construct( $requestFieldName, CollectionFactory $collectionFactory, \Magento\Framework\App\RequestInterface $request, + \Magento\Directory\Model\CountryFactory $countryFactory, array $meta = [], array $data = [] ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); $this->collection = $collectionFactory->create(); + $this->countryDirectory = $countryFactory->create(); $this->request = $request; } @@ -55,7 +63,7 @@ public function getData(): array } foreach ($data['items'] as $key => $item) { if (isset($item['country_id']) && !isset($item['country'])) { - $data['items'][$key]['country'] = $item['country_id']; + $data['items'][$key]['country'] = $this->countryDirectory->loadByCode($item['country_id'])->getName(); } } diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index bcc5b86c5e65d..4aeb7d67ace68 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -181,7 +181,7 @@ </validation> </settings> </field> - <field name="country_id" component="Magento_Ui/js/form/element/country" sortOrder="90" formElement="select"> + <field name="country_id" component="Magento_Customer/js/form/element/country" sortOrder="90" formElement="select"> <settings> <validation> <rule name="required-entry" xsi:type="boolean">true</rule> @@ -196,7 +196,7 @@ </select> </formElements> </field> - <field name="region_id" component="Magento_Ui/js/form/element/region" formElement="select"> + <field name="region_id" component="Magento_Customer/js/form/element/region" formElement="select"> <settings> <validation> <rule name="required-entry" xsi:type="boolean">true</rule> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js index 0dd828b03b419..4e8952e9e2a9d 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js @@ -4,8 +4,9 @@ */ define([ - 'Magento_Ui/js/form/components/insert-listing' -], function (Insert) { + 'Magento_Ui/js/form/components/insert-listing', + 'underscore' +], function (Insert, _) { 'use strict'; return Insert.extend({ @@ -25,29 +26,28 @@ define([ }, deleteAction: function (data) { + this._delete([parseFloat(data[data['id_field_name']])]); + }, + + deleteMassaction: function (data) { + var ids = _.map(data, function (val) { + return parseFloat(val); + }); + + this._delete(ids); + }, + + _delete: function (ids) { var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); - if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { + if (ids.indexOf(defaultShippingId) !== -1) { this.source.set('data.default_shipping_address', []); } - if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { + + if (ids.indexOf(defaultBillingId) !== -1) { this.source.set('data.default_billing_address', []); } - }, - - //TODO: release logic with massaction - deleteMassaction: function (data) { - debugger; - // var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), - // defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); - // - // if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { - // this.source.set('data.default_shipping_address', []); - // } - // if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { - // this.source.set('data.default_billing_address', []); - // } } }); }); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js new file mode 100644 index 0000000000000..bc60cf7a08fda --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js @@ -0,0 +1,27 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/country' +], function (Country) { + 'use strict'; + + return Country.extend({ + defaults: { + countryScope: 'data.country' + }, + + setDifferedFromDefault: function (value) { + this._super(); + + if (value) { + this.source.set(this.countryScope, this.indexedOptions[value].label); + } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js new file mode 100644 index 0000000000000..a9013577a1026 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js @@ -0,0 +1,27 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/region' +], function (Region) { + 'use strict'; + + return Region.extend({ + defaults: { + regionScope: 'data.region' + }, + + setDifferedFromDefault: function (value) { + this._super(); + + if (parseFloat(value)) { + this.source.set(this.regionScope, this.indexedOptions[value].label); + } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js index 1aefa2e249958..2477ef2672e68 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js @@ -49,11 +49,12 @@ define([ _.extend(selections, data.params || {}); + console.log(selections); this.request(action.url, selections).done(function (response) { if (!response.error) { this.trigger('massaction', { action: action.type, - data: selections + data: this.selections().selected() }); } }.bind(this)); diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html index 96158e9921e22..96de88a1145f4 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -16,8 +16,8 @@ <br/> </if> <if args="address.street"> - <text args="address.street" ifnot="_.isArray(address.street)"/> - <text args="_.values(address.street).join(', ')" if="_.isArray(address.street)"/> + <text args="address.street" if="_.isString(address.street)"/> + <text args="_.values(address.street).join(', ')" ifnot="_.isString(address.street)"/> <br/> </if> <text args="address.city + ', '" if="address.city"/> From 815f013d2a04212f69ae84871eb2d22ea60efcad Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Mon, 12 Nov 2018 16:17:38 -0600 Subject: [PATCH 0626/1158] #2331: Fixing static tests --- app/code/Magento/Customer/Controller/Section/Load.php | 2 +- app/code/Magento/Customer/CustomerData/Section/Identifier.php | 2 +- app/code/Magento/Customer/CustomerData/SectionPool.php | 2 +- .../Magento/Customer/Controller/Section/LoadTest.php | 4 +++- lib/internal/Magento/Framework/Test/Unit/TranslateTest.php | 1 + 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Section/Load.php b/app/code/Magento/Customer/Controller/Section/Load.php index 89d4417c79c19..37cd071b13623 100644 --- a/app/code/Magento/Customer/Controller/Section/Load.php +++ b/app/code/Magento/Customer/Controller/Section/Load.php @@ -59,7 +59,7 @@ public function __construct( } /** - * @return \Magento\Framework\Controller\Result\Json + * @inheritdoc */ public function execute() { diff --git a/app/code/Magento/Customer/CustomerData/Section/Identifier.php b/app/code/Magento/Customer/CustomerData/Section/Identifier.php index 54d7cee2d90bd..a8bc2c8abc11a 100644 --- a/app/code/Magento/Customer/CustomerData/Section/Identifier.php +++ b/app/code/Magento/Customer/CustomerData/Section/Identifier.php @@ -67,7 +67,7 @@ public function initMark($forceNewTimestamp) * Mark sections with data id * * @param array $sectionsData - * @param null $sectionNames + * @param array|null $sectionNames * @param bool $forceNewTimestamp * @return array */ diff --git a/app/code/Magento/Customer/CustomerData/SectionPool.php b/app/code/Magento/Customer/CustomerData/SectionPool.php index 618d52079973d..efea1762d9de6 100644 --- a/app/code/Magento/Customer/CustomerData/SectionPool.php +++ b/app/code/Magento/Customer/CustomerData/SectionPool.php @@ -53,7 +53,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getSectionsData(array $sectionNames = null, $forceNewTimestamp = false) { diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php index 3563087d3722b..3db22b8379850 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php @@ -13,7 +13,9 @@ public function testLoadInvalidSection() $expected = [ 'message' => 'The "section<invalid" section source isn't supported.', ]; - $this->dispatch('/customer/section/load/?sections=section<invalid&force_new_section_timestamp=false&_=147066166394'); + $this->dispatch( + '/customer/section/load/?sections=section<invalid&force_new_section_timestamp=false&_=147066166394' + ); self::assertEquals(json_encode($expected), $this->getResponse()->getBody()); } } diff --git a/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php b/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php index 885be8557fa10..0ec27d6d053c3 100644 --- a/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/TranslateTest.php @@ -11,6 +11,7 @@ use Magento\Framework\Translate; /** + * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class TranslateTest extends \PHPUnit\Framework\TestCase From ccda9172c70ddf00435641624d3814061e23f791 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 12 Nov 2018 16:55:54 -0600 Subject: [PATCH 0627/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Added condition --- .../Catalog/Controller/Adminhtml/Category/Index.php | 1 + .../GroupedProduct/Model/Product/Type/Grouped.php | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php index 5089b37f90c58..47969a4eca9ec 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php @@ -7,6 +7,7 @@ namespace Magento\Catalog\Controller\Adminhtml\Category; use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; +use Magento\Framework\Url\EncoderInterface; class Index extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface { diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index afa94e2b0b7a2..e54cb79b7b4e7 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -208,9 +208,10 @@ public function getParentIdsByChild($childId) * Retrieve array of associated products * * @param \Magento\Catalog\Model\Product $product + * @param bool $includeOutOfStock * @return array */ - public function getAssociatedProducts($product) + public function getAssociatedProducts($product, bool $includeOutOfStock = true) { if (!$product->hasData($this->_keyAssociatedProducts)) { $associatedProducts = []; @@ -228,7 +229,9 @@ public function getAssociatedProducts($product) ['in' => $this->getStatusFilters($product)] ); - $this->stockHelper->addIsInStockFilterToCollection($collection); + if (!$includeOutOfStock) { + $this->stockHelper->addIsInStockFilterToCollection($collection); + } foreach ($collection as $item) { $associatedProducts[] = $item; @@ -349,7 +352,7 @@ public function getAssociatedProductCollection($product) protected function getProductInfo(\Magento\Framework\DataObject $buyRequest, $product, $isStrictProcessMode) { $productsInfo = $buyRequest->getSuperGroup() ?: []; - $associatedProducts = $this->getAssociatedProducts($product); + $associatedProducts = $this->getAssociatedProducts($product, !empty($productsInfo)); if (!is_array($productsInfo)) { return __('Please specify the quantity of product(s).')->render(); From 0e59e8c244463d74e7949bbb1710d13f1990537d Mon Sep 17 00:00:00 2001 From: saphal <saphal.jha@krishtechnolabs.com> Date: Tue, 13 Nov 2018 10:36:08 +0530 Subject: [PATCH 0628/1158] code updated as per instructions --- app/code/Magento/Review/Model/ResourceModel/Rating.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating.php b/app/code/Magento/Review/Model/ResourceModel/Rating.php index 77a9727bd849e..04dce420ae522 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating.php @@ -425,11 +425,11 @@ public function getReviewSummary($object, $onlyForCurrentStore = true) $data = $connection->fetchAll($select, [':review_id' => $object->getReviewId()]); - $currentStore = ($this->_storeManager->isSingleStoreMode()) ? $this->_storeManager->getStore()->getId() : NULL ; + $currentStore = ($this->_storeManager->isSingleStoreMode()) ? $this->_storeManager->getStore()->getId() : null ; if ($onlyForCurrentStore) { foreach ($data as $row) { - if (!$row['store_id'] == $currentStore) { + if ($row['store_id'] !== $currentStore) { $object->addData($row); } } From 993ba971580958cdcdb779c80c193bd86183776c Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Tue, 13 Nov 2018 09:47:20 +0200 Subject: [PATCH 0629/1158] Adjusting the Unit Test strictness --- .../CheckUserLoginBackendObserverTest.php | 76 +++++-------------- 1 file changed, 18 insertions(+), 58 deletions(-) diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php index 02f6bed520acd..2d0a2a7e1c99a 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php @@ -14,7 +14,6 @@ use Magento\Framework\App\RequestInterface; use Magento\Framework\Event; use Magento\Framework\Event\Observer; -use Magento\Framework\Exception\Plugin\AuthenticationException; use Magento\Framework\Message\ManagerInterface; use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -71,14 +70,11 @@ protected function setUp() /** * Test check user login in backend with correct captcha * - * @dataProvider captchaCorrectnessCheckDataProvider + * @dataProvider requiredCaptchaDataProvider * @param bool $isRequired - * @param bool $isCorrect - * @param int $invokedTimes * @return void - * @throws AuthenticationException */ - public function testCheckOnBackendLoginWithCorrectCaptcha(bool $isRequired, bool $isCorrect, int $invokedTimes): void + public function testCheckOnBackendLoginWithCorrectCaptcha(bool $isRequired): void { $formId = 'backend_login'; $login = 'admin'; @@ -89,44 +85,25 @@ public function testCheckOnBackendLoginWithCorrectCaptcha(bool $isRequired, bool $eventMock = $this->createPartialMock(Event::class, ['getUsername']); $captcha = $this->createMock(DefaultModel::class); - $eventMock->expects($this->any()) - ->method('getUsername') - ->willReturn('admin'); - $observerMock->expects($this->any()) - ->method('getEvent') - ->willReturn($eventMock); - $captcha->expects($this->once())->method('isRequired') - ->with($login) - ->willReturn($isRequired); - $captcha->expects($this->exactly($invokedTimes)) - ->method('isCorrect') - ->with($captchaValue) - ->willReturn($isCorrect); - $this->helperMock->expects($this->once()) - ->method('getCaptcha') - ->with($formId) - ->willReturn($captcha); - - $this->captchaStringResolverMock->expects($this->exactly($invokedTimes)) - ->method('resolve') - ->with($this->requestMock, $formId) + $eventMock->method('getUsername')->willReturn('admin'); + $observerMock->method('getEvent')->willReturn($eventMock); + $captcha->method('isRequired')->with($login)->willReturn($isRequired); + $captcha->method('isCorrect')->with($captchaValue)->willReturn(true); + $this->helperMock->method('getCaptcha')->with($formId)->willReturn($captcha); + $this->captchaStringResolverMock->method('resolve')->with($this->requestMock, $formId) ->willReturn($captchaValue); - $this->messageManagerMock->expects($this->exactly(0)) - ->method('addError') - ->with(__('Incorrect CAPTCHA')); - $this->observer->execute($observerMock); } /** * @return array */ - public function captchaCorrectnessCheckDataProvider(): array + public function requiredCaptchaDataProvider(): array { return [ - [true, true, 1], - [false, true, 0] + [true], + [false] ]; } @@ -135,7 +112,7 @@ public function captchaCorrectnessCheckDataProvider(): array * Test check user login in backend with wrong captcha * * @return void - * @throws AuthenticationException + * @expectedException \Magento\Framework\Exception\Plugin\AuthenticationException */ public function testCheckOnBackendLoginWithWrongCaptcha(): void { @@ -148,31 +125,14 @@ public function testCheckOnBackendLoginWithWrongCaptcha(): void $eventMock = $this->createPartialMock(Event::class, ['getUsername']); $captcha = $this->createMock(DefaultModel::class); - $eventMock->expects($this->any()) - ->method('getUsername') - ->willReturn('admin'); - $observerMock->expects($this->any()) - ->method('getEvent') - ->willReturn($eventMock); - $captcha->expects($this->once())->method('isRequired') - ->with($login) - ->willReturn(true); - $captcha->expects($this->exactly(1)) - ->method('isCorrect') - ->with($captchaValue) - ->willReturn(false); - $this->helperMock->expects($this->once()) - ->method('getCaptcha') - ->with($formId) - ->willReturn($captcha); - - $this->captchaStringResolverMock->expects($this->exactly(1)) - ->method('resolve') - ->with($this->requestMock, $formId) + $eventMock->method('getUsername')->willReturn($login); + $observerMock->method('getEvent')->willReturn($eventMock); + $captcha->method('isRequired')->with($login)->willReturn(true); + $captcha->method('isCorrect')->with($captchaValue)->willReturn(false); + $this->helperMock->method('getCaptcha')->with($formId)->willReturn($captcha); + $this->captchaStringResolverMock->method('resolve')->with($this->requestMock, $formId) ->willReturn($captchaValue); - $this->expectException(AuthenticationException::class); - $this->observer->execute($observerMock); } } From 8f463db4808afc9f8f4908a4dee65f3abe981eba Mon Sep 17 00:00:00 2001 From: vgelani <vishalgelani99@gmail.com> Date: Mon, 22 Oct 2018 18:23:19 +0530 Subject: [PATCH 0630/1158] Added tier price logic for special price --- .../Model/Product/Attribute/Backend/Tierprice.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index 92b9a2e4239b2..55b5c6c925b05 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -159,8 +159,22 @@ protected function validatePrice(array $priceRow) */ protected function modifyPriceData($object, $data) { + /** @var \Magento\Catalog\Model\Product $object */ $data = parent::modifyPriceData($object, $data); $price = $object->getPrice(); + + $specialPrice = $object->getSpecialPrice(); + $specialPriceFromDate = $object->getSpecialFromDate(); + $specialPriceToDate = $object->getSpecialToDate(); + $today = time(); + + if ($specialPrice && ($object->getPrice() > $object->getFinalPrice())){ + if ($today >= strtotime($specialPriceFromDate) && $today <= strtotime($specialPriceToDate) || + $today >= strtotime($specialPriceFromDate) && is_null($specialPriceToDate)) { + $price = $specialPrice; + } + } + foreach ($data as $key => $tierPrice) { $percentageValue = $this->getPercentage($tierPrice); if ($percentageValue) { From 63c9ea46673e58f2712da5a768d0840ece184152 Mon Sep 17 00:00:00 2001 From: Vishal Gelani <vishalgelani99@gmail.com> Date: Tue, 23 Oct 2018 08:19:55 +0530 Subject: [PATCH 0631/1158] Fixed code standard error --- .../Catalog/Model/Product/Attribute/Backend/Tierprice.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index 55b5c6c925b05..88d8198d0249e 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -168,9 +168,9 @@ protected function modifyPriceData($object, $data) $specialPriceToDate = $object->getSpecialToDate(); $today = time(); - if ($specialPrice && ($object->getPrice() > $object->getFinalPrice())){ + if ($specialPrice && ($object->getPrice() > $object->getFinalPrice())) { if ($today >= strtotime($specialPriceFromDate) && $today <= strtotime($specialPriceToDate) || - $today >= strtotime($specialPriceFromDate) && is_null($specialPriceToDate)) { + $today >= strtotime($specialPriceFromDate) && is_null($specialPriceToDate) === TRUE) { $price = $specialPrice; } } From 77492c1c08695753b3a274b02552fab7be9c64c0 Mon Sep 17 00:00:00 2001 From: Vishal Gelani <vishalgelani99@gmail.com> Date: Tue, 23 Oct 2018 16:27:07 +0530 Subject: [PATCH 0632/1158] Update Tierprice.php --- .../Catalog/Model/Product/Attribute/Backend/Tierprice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index 88d8198d0249e..b74be1372a3c0 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -170,7 +170,7 @@ protected function modifyPriceData($object, $data) if ($specialPrice && ($object->getPrice() > $object->getFinalPrice())) { if ($today >= strtotime($specialPriceFromDate) && $today <= strtotime($specialPriceToDate) || - $today >= strtotime($specialPriceFromDate) && is_null($specialPriceToDate) === TRUE) { + $today >= strtotime($specialPriceFromDate) && is_null($specialPriceToDate)) { $price = $specialPrice; } } From d0ba9973dffac27560364906b22786d70410d69d Mon Sep 17 00:00:00 2001 From: Vishal Gelani <vishalgelani99@gmail.com> Date: Thu, 1 Nov 2018 17:59:10 +0530 Subject: [PATCH 0633/1158] Update Tierprice.php --- .../Catalog/Model/Product/Attribute/Backend/Tierprice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index b74be1372a3c0..23b2dfa01bfbd 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -170,7 +170,7 @@ protected function modifyPriceData($object, $data) if ($specialPrice && ($object->getPrice() > $object->getFinalPrice())) { if ($today >= strtotime($specialPriceFromDate) && $today <= strtotime($specialPriceToDate) || - $today >= strtotime($specialPriceFromDate) && is_null($specialPriceToDate)) { + $today >= strtotime($specialPriceFromDate) && $specialPriceToDate === null) { $price = $specialPrice; } } From e697698a5be421e215f6bab5454d706eed97fb6e Mon Sep 17 00:00:00 2001 From: Magently <hello@magently.com> Date: Fri, 24 Aug 2018 16:58:02 +0200 Subject: [PATCH 0634/1158] Fix addExpressionFieldToSelect method generated columns get overwriten by addFieldToSelect() --- .../Model/ResourceModel/Db/Collection/AbstractCollection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php index b57755ed7eafa..a88e013f5d2fe 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php @@ -346,7 +346,9 @@ public function addExpressionFieldToSelect($alias, $expression, $fields) $fullExpression = str_replace('{{' . $fieldKey . '}}', $fieldItem, $fullExpression); } - $this->getSelect()->columns([$alias => $fullExpression]); + $fullExpression = new \Zend_Db_Expr($fullExpression); + $this->_fieldsToSelect[$alias] = $fullExpression; + $this->_fieldsToSelectChanged = true; return $this; } From 3050d2367c284bded10815e7cd559b7bc3937546 Mon Sep 17 00:00:00 2001 From: Magently <hello@magently.com> Date: Tue, 4 Sep 2018 13:53:08 +0200 Subject: [PATCH 0635/1158] Fix integration test Changed test method to fit the new implementation of the class method --- .../ResourceModel/Db/Collection/AbstractCollectionTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php index 4f27f083509d7..7989a265e0db1 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php @@ -267,10 +267,11 @@ public function addFieldToSelectDataProvider() /** * @dataProvider addExpressionFieldToSelectDataProvider */ - public function testAddExpressionFieldToSelect($alias, $expression, $fields, $expected) + public function testAddExpressionFieldToSelect($alias, $expression, $fields, $expectedFieldsToSelect) { - $this->selectMock->expects($this->once())->method('columns')->with($expected); $this->assertTrue($this->uut->addExpressionFieldToSelect($alias, $expression, $fields) instanceof Uut); + $this->assertEquals($expectedFieldsToSelect, $this->uut->getFieldsToSelect()); + $this->assertTrue($this->uut->wereFieldsToSelectChanged()); } /** From 99ea1956fd75f7aeef809c90a3ec45f2cdbbd619 Mon Sep 17 00:00:00 2001 From: Magently <hello@magently.com> Date: Tue, 4 Sep 2018 15:24:11 +0200 Subject: [PATCH 0636/1158] Fix variable name in test class too long --- .../ResourceModel/Db/Collection/AbstractCollectionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php index 7989a265e0db1..0eae94dabbbe8 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php @@ -267,10 +267,10 @@ public function addFieldToSelectDataProvider() /** * @dataProvider addExpressionFieldToSelectDataProvider */ - public function testAddExpressionFieldToSelect($alias, $expression, $fields, $expectedFieldsToSelect) + public function testAddExpressionFieldToSelect($alias, $expression, $fields, $expected) { $this->assertTrue($this->uut->addExpressionFieldToSelect($alias, $expression, $fields) instanceof Uut); - $this->assertEquals($expectedFieldsToSelect, $this->uut->getFieldsToSelect()); + $this->assertEquals($expected, $this->uut->getFieldsToSelect()); $this->assertTrue($this->uut->wereFieldsToSelectChanged()); } From b1bf89323d5bd6a84f45dd3c7788b2c60312b345 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" <lopukhov@adobe.com> Date: Tue, 13 Nov 2018 10:23:41 +0200 Subject: [PATCH 0637/1158] MAGETWO-96118: Few optimizations on category & product pages --- .../Model/Product/Gallery/ReadHandler.php | 41 +++------------- .../Model/ResourceModel/Product/Gallery.php | 13 +++-- .../ResourceModel/Product/GalleryTest.php | 48 +++++++++++++++---- app/code/Magento/Catalog/etc/db_schema.xml | 5 ++ .../Catalog/etc/db_schema_whitelist.json | 5 +- .../Model/Product/Type/Configurable.php | 44 +++++++++++++---- .../Product/Type/Configurable.php | 11 +++-- .../Pricing/Renderer/SalableResolver.php | 4 +- .../Plugin/ExternalVideoResourceBackend.php | 40 ++++++++-------- 9 files changed, 127 insertions(+), 84 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php index c785d08e64b7f..4ad275bc70f90 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php @@ -55,9 +55,6 @@ public function __construct( */ public function execute($entity, $arguments = []) { - $value = []; - $value['images'] = []; - $mediaEntries = $this->resourceModel->loadProductGalleryByAttributeId( $entity, $this->getAttribute()->getAttributeId() @@ -79,37 +76,13 @@ public function execute($entity, $arguments = []) */ public function addMediaDataToProduct(Product $product, array $mediaEntries) { - $attrCode = $this->getAttribute()->getAttributeCode(); - $value = []; - $value['images'] = []; - $value['values'] = []; - - foreach ($mediaEntries as $mediaEntry) { - $mediaEntry = $this->substituteNullsWithDefaultValues($mediaEntry); - $value['images'][$mediaEntry['value_id']] = $mediaEntry; - } - $product->setData($attrCode, $value); - } - - /** - * @param array $rawData - * @return array - */ - private function substituteNullsWithDefaultValues(array $rawData) - { - $processedData = []; - foreach ($rawData as $key => $rawValue) { - if (null !== $rawValue) { - $processedValue = $rawValue; - } elseif (isset($rawData[$key . '_default'])) { - $processedValue = $rawData[$key . '_default']; - } else { - $processedValue = null; - } - $processedData[$key] = $processedValue; - } - - return $processedData; + $product->setData( + $this->getAttribute()->getAttributeCode(), + [ + 'images' => array_column($mediaEntries, null, 'value_id'), + 'values' => [] + ] + ); } /** diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php index 2868392f85280..b68c43e40ff2f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php @@ -190,7 +190,7 @@ public function createBatchBaseSelect($storeId, $attributeId) 'value.' . $linkField . ' = entity.' . $linkField, ] ), - ['label', 'position', 'disabled'] + [] )->joinLeft( ['default_value' => $this->getTable(self::GALLERY_VALUE_TABLE)], implode( @@ -201,8 +201,15 @@ public function createBatchBaseSelect($storeId, $attributeId) 'default_value.' . $linkField . ' = entity.' . $linkField, ] ), - ['label_default' => 'label', 'position_default' => 'position', 'disabled_default' => 'disabled'] - )->where( + [] + )->columns([ + 'label' => $this->getConnection()->getIfNullSql('`value`.`label`', '`default_value`.`label`'), + 'position' => $this->getConnection()->getIfNullSql('`value`.`position`', '`default_value`.`position`'), + 'disabled' => $this->getConnection()->getIfNullSql('`value`.`disabled`', '`default_value`.`disabled`'), + 'label_default' => 'default_value.label', + 'position_default' => 'default_value.position', + 'disabled_default' => 'default_value.disabled' + ])->where( $mainTableAlias . '.attribute_id = ?', $attributeId )->where( diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/GalleryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/GalleryTest.php index dfed4e4f37385..47ef3c999125f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/GalleryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/GalleryTest.php @@ -281,6 +281,9 @@ public function testBindValueToEntityRecordExists() $this->resource->bindValueToEntity($valueId, $entityId); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testLoadGallery() { $productId = 5; @@ -329,7 +332,8 @@ public function testLoadGallery() 'main.value_id = entity.value_id', ['entity_id'] )->willReturnSelf(); - $this->product->expects($this->at(0))->method('getData')->with('entity_id')->willReturn($productId); + $this->product->expects($this->at(0))->method('getData') + ->with('entity_id')->willReturn($productId); $this->product->expects($this->at(1))->method('getStoreId')->will($this->returnValue($storeId)); $this->connection->expects($this->exactly(2))->method('quoteInto')->withConsecutive( ['value.store_id = ?'], @@ -338,26 +342,50 @@ public function testLoadGallery() 'value.store_id = ' . $storeId, 'default_value.store_id = ' . 0 ); + $this->connection->expects($this->any())->method('getIfNullSql')->will( + $this->returnValueMap([ + [ + '`value`.`label`', + '`default_value`.`label`', + 'IFNULL(`value`.`label`, `default_value`.`label`)' + ], + [ + '`value`.`position`', + '`default_value`.`position`', + 'IFNULL(`value`.`position`, `default_value`.`position`)' + ], + [ + '`value`.`disabled`', + '`default_value`.`disabled`', + 'IFNULL(`value`.`disabled`, `default_value`.`disabled`)' + ] + ]) + ); $this->select->expects($this->at(2))->method('joinLeft')->with( ['value' => $getTableReturnValue], $quoteInfoReturnValue, - [ - 'label', - 'position', - 'disabled' - ] + [] )->willReturnSelf(); $this->select->expects($this->at(3))->method('joinLeft')->with( ['default_value' => $getTableReturnValue], $quoteDefaultInfoReturnValue, - ['label_default' => 'label', 'position_default' => 'position', 'disabled_default' => 'disabled'] + [] )->willReturnSelf(); - $this->select->expects($this->at(4))->method('where')->with( + $this->select->expects($this->at(4))->method('columns')->with([ + 'label' => 'IFNULL(`value`.`label`, `default_value`.`label`)', + 'position' => 'IFNULL(`value`.`position`, `default_value`.`position`)', + 'disabled' => 'IFNULL(`value`.`disabled`, `default_value`.`disabled`)', + 'label_default' => 'default_value.label', + 'position_default' => 'default_value.position', + 'disabled_default' => 'default_value.disabled' + ])->willReturnSelf(); + $this->select->expects($this->at(5))->method('where')->with( 'main.attribute_id = ?', $attributeId )->willReturnSelf(); - $this->select->expects($this->at(5))->method('where')->with('main.disabled = 0')->willReturnSelf(); - $this->select->expects($this->at(7))->method('where') + $this->select->expects($this->at(6))->method('where') + ->with('main.disabled = 0')->willReturnSelf(); + $this->select->expects($this->at(8))->method('where') ->with('entity.entity_id = ?', $productId) ->willReturnSelf(); $this->select->expects($this->once())->method('order') diff --git a/app/code/Magento/Catalog/etc/db_schema.xml b/app/code/Magento/Catalog/etc/db_schema.xml index a366065c89e76..8dcc623dd64dd 100644 --- a/app/code/Magento/Catalog/etc/db_schema.xml +++ b/app/code/Magento/Catalog/etc/db_schema.xml @@ -835,6 +835,11 @@ <index referenceId="CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID" indexType="btree"> <column name="value_id"/> </index> + <index referenceId="CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_ENTITY_ID_VALUE_ID_STORE_ID" indexType="btree"> + <column name="entity_id"/> + <column name="value_id"/> + <column name="store_id"/> + </index> </table> <table name="catalog_product_option" resource="default" engine="innodb" comment="Catalog Product Option Table"> <column xsi:type="int" name="option_id" padding="10" unsigned="true" nullable="false" identity="true" diff --git a/app/code/Magento/Catalog/etc/db_schema_whitelist.json b/app/code/Magento/Catalog/etc/db_schema_whitelist.json index b1543a6a007f9..31620e4e920f4 100644 --- a/app/code/Magento/Catalog/etc/db_schema_whitelist.json +++ b/app/code/Magento/Catalog/etc/db_schema_whitelist.json @@ -484,7 +484,8 @@ "index": { "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_STORE_ID": true, "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_ENTITY_ID": true, - "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID": true + "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID": true, + "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_ENTITY_ID_VALUE_ID_STORE_ID": true }, "constraint": { "PRIMARY": true, @@ -1121,4 +1122,4 @@ "CATALOG_PRODUCT_FRONTEND_ACTION_CUSTOMER_ID_PRODUCT_ID_TYPE_ID": true } } -} \ No newline at end of file +} diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php index 19de63b7a976c..f98075f2294cc 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php @@ -453,6 +453,10 @@ public function getConfigurableAttributes($product) ['group' => 'CONFIGURABLE', 'method' => __METHOD__] ); if (!$product->hasData($this->_configurableAttributes)) { + // for new product do not load configurable attributes + if (!$product->getId()) { + return []; + } $configurableAttributes = $this->getConfigurableAttributeCollection($product); $this->extensionAttributesJoinProcessor->process($configurableAttributes); $configurableAttributes->orderByPosition()->load(); @@ -1398,23 +1402,47 @@ private function getConfiguredUsedProductCollection( $skipStockFilter = true ) { $collection = $this->getUsedProductCollection($product); + if ($skipStockFilter) { $collection->setFlag('has_stock_status_filter', true); } + $collection - ->addAttributeToSelect($this->getCatalogConfig()->getProductAttributes()) + ->addAttributeToSelect($this->getAttributesForCollection($product)) ->addFilterByRequiredOptions() ->setStoreId($product->getStoreId()); - $requiredAttributes = ['name', 'price', 'weight', 'image', 'thumbnail', 'status', 'media_gallery']; - foreach ($requiredAttributes as $attributeCode) { - $collection->addAttributeToSelect($attributeCode); - } - foreach ($this->getUsedProductAttributes($product) as $usedProductAttribute) { - $collection->addAttributeToSelect($usedProductAttribute->getAttributeCode()); - } $collection->addMediaGalleryData(); $collection->addTierPriceData(); + return $collection; } + + /** + * @return array + */ + private function getAttributesForCollection(\Magento\Catalog\Model\Product $product) + { + $productAttributes = $this->getCatalogConfig()->getProductAttributes(); + + $requiredAttributes = [ + 'name', + 'price', + 'weight', + 'image', + 'thumbnail', + 'status', + 'visibility', + 'media_gallery' + ]; + + $usedAttributes = array_map( + function($attr) { + return $attr->getAttributeCode(); + }, + $this->getUsedProductAttributes($product) + ); + + return array_unique(array_merge($productAttributes, $requiredAttributes, $usedAttributes)); + } } diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php index ccff85dd9717f..3611d95f0c6ac 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php @@ -173,10 +173,13 @@ public function getChildrenIds($parentId, $required = true) $parentId ); - $childrenIds = [0 => []]; - foreach ($this->getConnection()->fetchAll($select) as $row) { - $childrenIds[0][$row['product_id']] = $row['product_id']; - } + $childrenIds = [ + 0 => array_column( + $this->getConnection()->fetchAll($select), + 'product_id', + 'product_id' + ) + ]; return $childrenIds; } diff --git a/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php b/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php index efddb278df36c..8a7e846c0e9f1 100644 --- a/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php +++ b/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php @@ -44,9 +44,7 @@ public function afterIsSalable( \Magento\Framework\Pricing\SaleableInterface $salableItem ) { if ($salableItem->getTypeId() == 'configurable' && $result) { - if (!$this->lowestPriceOptionsProvider->getProducts($salableItem)) { - $result = false; - } + $result = $salableItem->isSalable(); } return $result; diff --git a/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php b/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php index dc64f03a42d19..b27c7c8976b4c 100644 --- a/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php +++ b/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php @@ -60,19 +60,9 @@ public function afterCreateBatchBaseSelect(Gallery $originalResourceModel, Selec 'value.store_id = value_video.store_id', ] ), - [ - 'video_provider' => 'provider', - 'video_url' => 'url', - 'video_title' => 'title', - 'video_description' => 'description', - 'video_metadata' => 'metadata' - ] + [] )->joinLeft( - [ - 'default_value_video' => $originalResourceModel->getTable( - 'catalog_product_entity_media_gallery_value_video' - ) - ], + ['default_value_video' => $originalResourceModel->getTable('catalog_product_entity_media_gallery_value_video')], implode( ' AND ', [ @@ -80,14 +70,24 @@ public function afterCreateBatchBaseSelect(Gallery $originalResourceModel, Selec 'default_value.store_id = default_value_video.store_id', ] ), - [ - 'video_provider_default' => 'provider', - 'video_url_default' => 'url', - 'video_title_default' => 'title', - 'video_description_default' => 'description', - 'video_metadata_default' => 'metadata', - ] - ); + [] + )->columns([ + 'video_provider' => $originalResourceModel->getConnection() + ->getIfNullSql('`value_video`.`provider`', '`default_value_video`.`provider`'), + 'video_url' => $originalResourceModel->getConnection() + ->getIfNullSql('`value_video`.`url`', '`default_value_video`.`url`'), + 'video_title' => $originalResourceModel->getConnection() + ->getIfNullSql('`value_video`.`title`', '`default_value_video`.`title`'), + 'video_description' => $originalResourceModel->getConnection() + ->getIfNullSql('`value_video`.`description`', '`default_value_video`.`description`'), + 'video_metadata' => $originalResourceModel->getConnection() + ->getIfNullSql('`value_video`.`metadata`', '`default_value_video`.`metadata`'), + 'video_provider_default' => 'default_value_video.provider', + 'video_url_default' => 'default_value_video.url', + 'video_title_default' => 'default_value_video.title', + 'video_description_default' => 'default_value_video.description', + 'video_metadata_default' => 'default_value_video.metadata', + ]); return $select; } From 6d6380f272824619cfcfafd8a3fa142e354d311c Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Tue, 13 Nov 2018 10:28:33 +0200 Subject: [PATCH 0638/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - change step on Credit memo page --- ...retateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml index 4feb47ae78e15..fe1ed76e77f70 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml @@ -109,6 +109,6 @@ <!--Get access to Credit Memo page from Invocie page--> <click selector="{{AdminInvoiceMainActionsSection.openNewCreditMemoFromInvoice}}" stepKey="clickCreateNewCreditMemo"/> <waitForPageLoad stepKey="waitForLoadNewCreditMemoPage" time="5"/> - <see selector="{{AdminCreditMemoOrderInformationSection.orderId}}" userInput="New Memo" stepKey="seeNewCreditMemo" after="waitForLoadNewCreditMemoPage"/> + <see selector="{{AdminCreditMemoOrderInformationSection.orderId}}" userInput="New Memo for" stepKey="seeNewCreditMemo" after="waitForLoadNewCreditMemoPage"/> </test> </tests> \ No newline at end of file From b1c944b69b3a7504fa3cda663694481debac362a Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" <lopukhov@adobe.com> Date: Tue, 13 Nov 2018 10:44:18 +0200 Subject: [PATCH 0639/1158] MAGETWO-96118: Few optimizations on category & product pages --- .../Model/Product/Gallery/ReadHandler.php | 8 ++++++++ .../Model/ResourceModel/Product/Gallery.php | 20 +++++++++++++++++-- .../Product/Type/Configurable.php | 3 +++ .../Pricing/Renderer/SalableResolver.php | 3 +-- .../Plugin/ExternalVideoResourceBackend.php | 10 +++++++++- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php index 4ad275bc70f90..a3726207b3024 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php @@ -47,6 +47,8 @@ public function __construct( } /** + * Execute read handler for catalog product gallery + * * @param Product $entity * @param array $arguments * @return object @@ -69,6 +71,8 @@ public function execute($entity, $arguments = []) } /** + * Add media data to product + * * @param Product $product * @param array $mediaEntries * @return void @@ -86,6 +90,8 @@ public function addMediaDataToProduct(Product $product, array $mediaEntries) } /** + * Get attribute + * * @return \Magento\Catalog\Api\Data\ProductAttributeInterface * @since 101.0.0 */ @@ -99,6 +105,8 @@ public function getAttribute() } /** + * Find default value + * * @param string $key * @param string[] &$image * @return string diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php index b68c43e40ff2f..635715a60742f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php @@ -49,7 +49,8 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc + * * @since 101.0.0 */ protected function _construct() @@ -58,7 +59,8 @@ protected function _construct() } /** - * {@inheritdoc} + * @inheritdoc + * * @since 101.0.0 */ public function getConnection() @@ -67,6 +69,8 @@ public function getConnection() } /** + * Load data from table by valueId + * * @param string $tableNameAlias * @param array $ids * @param int|null $storeId @@ -111,6 +115,8 @@ public function loadDataFromTableByValueId( } /** + * Load product gallery by attributeId + * * @param \Magento\Catalog\Model\Product $product * @param int $attributeId * @return array @@ -132,6 +138,8 @@ public function loadProductGalleryByAttributeId($product, $attributeId) } /** + * Create base load select + * * @param int $entityId * @param int $storeId * @param int $attributeId @@ -151,6 +159,8 @@ protected function createBaseLoadSelect($entityId, $storeId, $attributeId) } /** + * Create batch base select + * * @param int $storeId * @param int $attributeId * @return \Magento\Framework\DB\Select @@ -247,6 +257,8 @@ protected function removeDuplicates(&$result) } /** + * Get main table alias + * * @return string * @since 101.0.0 */ @@ -256,6 +268,8 @@ public function getMainTableAlias() } /** + * Bind value to entity + * * @param int $valueId * @param int $entityId * @return int @@ -273,6 +287,8 @@ public function bindValueToEntity($valueId, $entityId) } /** + * Save data row + * * @param string $table * @param array $data * @param array $fields diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php index 3611d95f0c6ac..feffd22a0fb3d 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php @@ -19,6 +19,9 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Adapter\AdapterInterface; +/** + * Configurable product resource model. + */ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb { /** diff --git a/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php b/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php index 8a7e846c0e9f1..df8782ae422b4 100644 --- a/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php +++ b/app/code/Magento/ConfigurableProduct/Plugin/Catalog/Model/Product/Pricing/Renderer/SalableResolver.php @@ -27,8 +27,7 @@ public function __construct( } /** - * Performs an additional check whether given configurable product has - * at least one configuration in-stock. + * Performs an additional check whether given configurable product has at least one configuration in-stock. * * @param \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver $subject * @param bool $result diff --git a/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php b/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php index b27c7c8976b4c..04a3d868d14a6 100644 --- a/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php +++ b/app/code/Magento/ProductVideo/Model/Plugin/ExternalVideoResourceBackend.php @@ -27,6 +27,8 @@ public function __construct(\Magento\ProductVideo\Model\ResourceModel\Video $vid } /** + * Plugin for after duplicate action + * * @param Gallery $originalResourceModel * @param array $valueIdMap * @return array @@ -45,6 +47,8 @@ public function afterDuplicate(Gallery $originalResourceModel, array $valueIdMap } /** + * Plugin for after create batch base select action + * * @param Gallery $originalResourceModel * @param Select $select * @return Select @@ -62,7 +66,11 @@ public function afterCreateBatchBaseSelect(Gallery $originalResourceModel, Selec ), [] )->joinLeft( - ['default_value_video' => $originalResourceModel->getTable('catalog_product_entity_media_gallery_value_video')], + [ + 'default_value_video' => $originalResourceModel->getTable( + 'catalog_product_entity_media_gallery_value_video' + ) + ], implode( ' AND ', [ From ffa44b557173be5fec38dac0494c42925e2ae677 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Tue, 13 Nov 2018 10:50:09 +0200 Subject: [PATCH 0640/1158] MAGETWO-96182: Adopt integration and API tests for implemented changes - Change mass delete action in customer address listing structure; --- .../ui_component/customer_address_listing.xml | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index b138a81e395a3..6d59977cda140 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -63,20 +63,18 @@ </settings> </filters> <massaction name="listing_massaction" component="Magento_Customer/js/grid/massactions"> - <settings> - <actions xsi:type="array"> - <item name="0" xsi:type="array"> - <item name="isAjax" xsi:type="boolean">true</item> - <item name="confirm" xsi:type="array"> - <item name="message" xsi:type="string" translate="true">Are you sure to delete selected address?</item> - <item name="title" xsi:type="string" translate="true">Delete items</item> - </item> - <item name="url" xsi:type="url" path="customer/address/massDelete"/> - <item name="type" xsi:type="string">delete</item> - <item name="label" xsi:type="string" translate="true">Delete</item> - </item> - </actions> - </settings> + <action name="customer_addresses_mass_delete"> + <settings> + <isAjax>true</isAjax> + <confirm> + <message translate="true">Are you sure to delete selected address?</message> + <title translate="true">Delete items + + + delete + + + From 4328497e27f38c9317b4a2731b08fbd61243a5ae Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Tue, 13 Nov 2018 10:37:02 +0100 Subject: [PATCH 0641/1158] Adjusted API-functional tests for new limits --- .../Framework/QueryComplexityLimiterTest.php | 132 ++++++++++++++++-- 1 file changed, 121 insertions(+), 11 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php index 3304d9e6198f4..9bf223068e226 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -24,7 +24,7 @@ public function testQueryComplexityIsLimited() $query = <<graphQlQuery($query); } From 436e3d3a6bf8179220747bef5cbdaeaaab4b730f Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Tue, 13 Nov 2018 12:58:32 +0300 Subject: [PATCH 0642/1158] MAGETWO-91725: Reward Points Balance Update Emails are not being sent when balance change initiated by store front - Fix webapi test --- .../Customer/Api/CustomerMetadataTest.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php index f2632aa1481e4..3b1d431342988 100644 --- a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php @@ -9,6 +9,7 @@ use Magento\Customer\Api\Data\CustomerInterface as Customer; use Magento\Customer\Model\Data\AttributeMetadata; use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\TestFramework\Helper\Bootstrap; /** * Class CustomerMetadataTest @@ -19,6 +20,19 @@ class CustomerMetadataTest extends WebapiAbstract const SERVICE_VERSION = "V1"; const RESOURCE_PATH = "/V1/attributeMetadata/customer"; + /** + * @var CustomerMetadataInterface + */ + private $customerMetadata; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $this->customerMetadata = Bootstrap::getObjectManager()->create(CustomerMetadataInterface::class); + } + /** * Test retrieval of attribute metadata for the customer entity type. * @@ -200,8 +214,7 @@ public function testGetCustomAttributesMetadata() $attributeMetadata = $this->_webApiCall($serviceInfo); - // There are no default custom attributes. - $this->assertCount(0, $attributeMetadata); + $this->assertCount(count($this->customerMetadata->getCustomAttributesMetadata()), $attributeMetadata); } /** From 1050136cd115936306c12176a281114f2dbe4d3a Mon Sep 17 00:00:00 2001 From: eduard13 Date: Tue, 13 Nov 2018 12:10:56 +0200 Subject: [PATCH 0643/1158] Adding integration tests for wrong captcha on login and forgotpassword pages --- ...successfulMessageWhenCaptchaFailedTest.php | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php diff --git a/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php b/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php new file mode 100644 index 0000000000000..cb2a98409bc24 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php @@ -0,0 +1,78 @@ +_objectManager->get(\Magento\Framework\Data\Form\FormKey::class); + $post = [ + 'login' => [ + 'username' => 'dummy@dummy.com', + 'password' => 'dummy_password1', + ], + 'captcha' => ['user_login' => 'wrong_captcha'], + 'form_key' => $formKey->getFormKey(), + ]; + + $this->getRequest()->setMethod(Request::METHOD_POST); + $this->getRequest()->setPostValue($post); + + $this->dispatch('customer/account/loginPost'); + + $this->assertRedirect($this->stringContains('customer/account/login')); + $this->assertSessionMessages( + $this->equalTo(['Incorrect CAPTCHA']), + MessageInterface::TYPE_ERROR + ); + } + + /** + * Test incorrect captcha on customer forgot password page + * + * @codingStandardsIgnoreStart + * @magentoConfigFixture current_store customer/password/limit_password_reset_requests_method 0 + * @magentoConfigFixture default_store customer/captcha/enable 1 + * @magentoConfigFixture default_store customer/captcha/forms user_forgotpassword + * @magentoConfigFixture default_store customer/captcha/mode always + */ + public function testForgotPasswordCheckUnsuccessfulMessageWhenCaptchaFailed() + { + $email = 'dummy@dummy.com'; + + $this->getRequest()->setPostValue(['email' => $email]); + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + + $this->dispatch('customer/account/forgotPasswordPost'); + + $this->assertRedirect($this->stringContains('customer/account/forgotpassword')); + $this->assertSessionMessages( + $this->equalTo(['Incorrect CAPTCHA']), + MessageInterface::TYPE_ERROR + ); + } +} From 19c1f871b6bb1853ad960edfc3f6c8372c8a3e4f Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Tue, 13 Nov 2018 11:40:06 +0100 Subject: [PATCH 0644/1158] API-functional tests coverage --- .../Catalog/CategoryProductsCountTest.php | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryProductsCountTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryProductsCountTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryProductsCountTest.php new file mode 100644 index 0000000000000..eddd456a7b866 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryProductsCountTest.php @@ -0,0 +1,143 @@ +productRepository = $objectManager->create(ProductRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testCategoryWithSaleableProduct() + { + $categoryId = 2; + + $query = <<graphQlQuery($query); + + self::assertEquals(1, $response['category']['product_count']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_product.php + */ + public function testCategoryWithInvisibleProduct() + { + $categoryId = 333; + $sku = 'simple333'; + + $product = $this->productRepository->get($sku); + $product->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE); + $this->productRepository->save($product); + + $query = <<graphQlQuery($query); + + self::assertEquals(0, $response['category']['product_count']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + */ + public function testCategoryWithOutOfStockProductManageStockEnabled() + { + $categoryId = 2; + + $query = <<graphQlQuery($query); + + self::assertEquals(0, $response['category']['product_count']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_product.php + */ + public function testCategoryWithOutOfStockProductManageStockDisabled() + { + $categoryId = 333; + + $query = <<graphQlQuery($query); + + self::assertEquals(1, $response['category']['product_count']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_product.php + */ + public function testCategoryWithDisabledProduct() + { + $categoryId = 333; + $sku = 'simple333'; + + $product = $this->productRepository->get($sku); + $product->setStatus(ProductStatus::STATUS_DISABLED); + $this->productRepository->save($product); + + $query = <<graphQlQuery($query); + + self::assertEquals(0, $response['category']['product_count']); + } +} From cbe6a4492e8b3d9ec8d75169c353d67685b99d55 Mon Sep 17 00:00:00 2001 From: eduard13 Date: Tue, 13 Nov 2018 12:45:21 +0200 Subject: [PATCH 0645/1158] Adding integration tests for wrong captcha on customer create page --- ...successfulMessageWhenCaptchaFailedTest.php | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php b/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php index cb2a98409bc24..8355d81fdf5d9 100644 --- a/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php +++ b/dev/tests/integration/testsuite/Magento/Captcha/Observer/CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest.php @@ -5,7 +5,7 @@ */ namespace Magento\Captcha\Observer; -use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Data\Form\FormKey; use Magento\Framework\Message\MessageInterface; use Magento\TestFramework\Request; use Magento\TestFramework\TestCase\AbstractController; @@ -28,8 +28,8 @@ class CaseCheckOnFrontendUnsuccessfulMessageWhenCaptchaFailedTest extends Abstra */ public function testLoginCheckUnsuccessfulMessageWhenCaptchaFailed() { - /** @var \Magento\Framework\Data\Form\FormKey $formKey */ - $formKey = $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class); + /** @var FormKey $formKey */ + $formKey = $this->_objectManager->get(FormKey::class); $post = [ 'login' => [ 'username' => 'dummy@dummy.com', @@ -39,8 +39,7 @@ public function testLoginCheckUnsuccessfulMessageWhenCaptchaFailed() 'form_key' => $formKey->getFormKey(), ]; - $this->getRequest()->setMethod(Request::METHOD_POST); - $this->getRequest()->setPostValue($post); + $this->prepareRequestData($post); $this->dispatch('customer/account/loginPost'); @@ -62,10 +61,8 @@ public function testLoginCheckUnsuccessfulMessageWhenCaptchaFailed() */ public function testForgotPasswordCheckUnsuccessfulMessageWhenCaptchaFailed() { - $email = 'dummy@dummy.com'; - - $this->getRequest()->setPostValue(['email' => $email]); - $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $post = ['email' => 'dummy@dummy.com']; + $this->prepareRequestData($post); $this->dispatch('customer/account/forgotPasswordPost'); @@ -75,4 +72,47 @@ public function testForgotPasswordCheckUnsuccessfulMessageWhenCaptchaFailed() MessageInterface::TYPE_ERROR ); } + + /** + * Test incorrect captcha on customer create account page + * + * @codingStandardsIgnoreStart + * @magentoConfigFixture current_store customer/password/limit_password_reset_requests_method 0 + * @magentoConfigFixture default_store customer/captcha/enable 1 + * @magentoConfigFixture default_store customer/captcha/forms user_create + * @magentoConfigFixture default_store customer/captcha/mode always + */ + public function testCreateAccountCheckUnsuccessfulMessageWhenCaptchaFailed() + { + /** @var FormKey $formKey */ + $formKey = $this->_objectManager->get(FormKey::class); + $post = [ + 'firstname' => 'Firstname', + 'lastname' => 'Lastname', + 'email' => 'dummy@dummy.com', + 'password' => 'TestPassword123', + 'password_confirmation' => 'TestPassword123', + 'captcha' => ['user_create' => 'wrong_captcha'], + 'form_key' => $formKey->getFormKey(), + ]; + $this->prepareRequestData($post); + + $this->dispatch('customer/account/createPost'); + + $this->assertRedirect($this->stringContains('customer/account/create')); + $this->assertSessionMessages( + $this->equalTo(['Incorrect CAPTCHA']), + MessageInterface::TYPE_ERROR + ); + } + + /** + * @param array $postData + * @return void + */ + private function prepareRequestData($postData) + { + $this->getRequest()->setMethod(Request::METHOD_POST); + $this->getRequest()->setPostValue($postData); + } } From c683dde7e44b30c81f55593c9275eb1f31dc7cb1 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" Date: Tue, 13 Nov 2018 13:09:09 +0200 Subject: [PATCH 0646/1158] MAGETWO-96118: Few optimizations on category & product pages --- app/code/Magento/Catalog/etc/db_schema.xml | 2 +- app/code/Magento/Catalog/etc/db_schema_whitelist.json | 2 +- .../Model/Product/Type/ConfigurableTest.php | 9 +++++++-- .../Framework/Interception/PluginList/PluginList.php | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/etc/db_schema.xml b/app/code/Magento/Catalog/etc/db_schema.xml index 8dcc623dd64dd..17e3dddc41c3b 100644 --- a/app/code/Magento/Catalog/etc/db_schema.xml +++ b/app/code/Magento/Catalog/etc/db_schema.xml @@ -835,7 +835,7 @@ - + diff --git a/app/code/Magento/Catalog/etc/db_schema_whitelist.json b/app/code/Magento/Catalog/etc/db_schema_whitelist.json index 31620e4e920f4..d4bd6927d4345 100644 --- a/app/code/Magento/Catalog/etc/db_schema_whitelist.json +++ b/app/code/Magento/Catalog/etc/db_schema_whitelist.json @@ -485,7 +485,7 @@ "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_STORE_ID": true, "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_ENTITY_ID": true, "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_VALUE_ID": true, - "CATALOG_PRODUCT_ENTITY_MEDIA_GALLERY_VALUE_ENTITY_ID_VALUE_ID_STORE_ID": true + "CAT_PRD_ENTT_MDA_GLR_VAL_ENTT_ID_VAL_ID_STORE_ID": true }, "constraint": { "PRIMARY": true, diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php index bdb36b93af21c..78fa4733a2562 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php @@ -4,6 +4,8 @@ * See COPYING.txt for license details. */ +// @codingStandardsIgnoreFile + namespace Magento\ConfigurableProduct\Model\Product\Type; use Magento\Catalog\Api\Data\ProductInterface; @@ -128,6 +130,10 @@ public function testGetUsedProductAttributes() $this->assertEquals($testConfigurable->getData(), $attributes[$attributeId]->getData()); } + /** + * @magentoAppIsolation enabled + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ public function testGetConfigurableAttributes() { $collection = $this->model->getConfigurableAttributes($this->product); @@ -332,8 +338,7 @@ public function testGetSelectedAttributesInfo() $attribute = reset($attributes); $optionValueId = $attribute['values'][0]['value_index']; - $product->addCustomOption( - 'attributes', + $product->addCustomOption('attributes', $serializer->serialize([$attribute['attribute_id'] => $optionValueId]) ); diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php index e21841b48bc13..d20cd57f4e43f 100644 --- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php +++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php @@ -264,7 +264,7 @@ public function getPlugin($type, $code) public function getNext($type, $method, $code = '__self') { $this->_loadScopedData(); - if (!isset($this->_inherited[$type]) && !array_key_exists($type, $this->_inherited)) { + if ($this->_inherited !== null && !isset($this->_inherited[$type]) && !array_key_exists($type, $this->_inherited)) { $this->_inheritPlugins($type); } $key = $type . '_' . lcfirst($method) . '_' . $code; From f4a0e6a6e0f484c6a5d4c469fdd84f027aa4aac8 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich Date: Tue, 13 Nov 2018 14:29:42 +0300 Subject: [PATCH 0647/1158] MAGETWO-62728: My Wishlist - quantity input box issue - Fixed static test; --- .../Wishlist/view/frontend/templates/item/column/cart.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml index 7578774fabc2c..848c6a76393f8 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml @@ -22,7 +22,7 @@ $allowedQty = $block->getMinMaxQty();
    -
    From c4b394a43f6e2690c3706eb5c5768a69185584d5 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" Date: Tue, 13 Nov 2018 13:56:45 +0200 Subject: [PATCH 0648/1158] MAGETWO-96118: Few optimizations on category & product pages --- .../Magento/Framework/Interception/PluginList/PluginList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php index d20cd57f4e43f..e21841b48bc13 100644 --- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php +++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php @@ -264,7 +264,7 @@ public function getPlugin($type, $code) public function getNext($type, $method, $code = '__self') { $this->_loadScopedData(); - if ($this->_inherited !== null && !isset($this->_inherited[$type]) && !array_key_exists($type, $this->_inherited)) { + if (!isset($this->_inherited[$type]) && !array_key_exists($type, $this->_inherited)) { $this->_inheritPlugins($type); } $key = $type . '_' . lcfirst($method) . '_' . $code; From 91157807e4e9bbb055b61d0f949535a816c172b6 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" Date: Tue, 13 Nov 2018 13:59:36 +0200 Subject: [PATCH 0649/1158] MAGETWO-96118: Few optimizations on category & product pages --- .../Model/Product/Type/ConfigurableTest.php | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php index 5e9399ddd3d65..d1cf77f03a7bd 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php @@ -27,6 +27,7 @@ * @SuppressWarnings(PHPMD.LongVariable) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.TooManyFields) + * @codingStandardsIgnoreFile */ class ConfigurableTest extends \PHPUnit\Framework\TestCase { @@ -154,8 +155,7 @@ protected function setUp() ->setMethods(['create']) ->getMock(); $this->productCollectionFactory = $this->getMockBuilder( - \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory::class - ) + \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); @@ -197,11 +197,6 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->productFactory = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterfaceFactory::class) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $this->salableProcessor = $this->createMock(SalableProcessor::class); $this->model = $this->objectHelper->getObject( @@ -287,8 +282,7 @@ public function testSave() ->method('getData') ->willReturnMap($dataMap); $attribute = $this->getMockBuilder( - \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class - ) + \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class) ->disableOriginalConstructor() ->setMethods(['addData', 'setStoreId', 'setProductId', 'save', '__wakeup', '__sleep']) ->getMock(); @@ -385,7 +379,7 @@ public function testGetUsedProducts() ['_cache_instance_used_product_attributes', null, []] ] ); - + $this->catalogConfig->expects($this->any())->method('getProductAttributes')->willReturn([]); $productCollection->expects($this->atLeastOnce())->method('addAttributeToSelect')->willReturnSelf(); $productCollection->expects($this->once())->method('setProductFilter')->willReturnSelf(); $productCollection->expects($this->atLeastOnce())->method('setFlag')->willReturnSelf(); @@ -471,8 +465,7 @@ public function testGetConfigurableAttributesAsArray($productStore) $eavAttribute->expects($this->atLeastOnce())->method('getStoreLabel')->willReturn('Store Label'); $attribute = $this->getMockBuilder( - \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class - ) + \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class) ->disableOriginalConstructor() ->setMethods(['getProductAttribute', '__wakeup', '__sleep']) ->getMock(); @@ -515,17 +508,34 @@ public function getConfigurableAttributesAsArrayDataProvider() ]; } - public function testGetConfigurableAttributes() + public function testGetConfigurableAttributesNewProduct() { $configurableAttributes = '_cache_instance_configurable_attributes'; /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */ $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) - ->setMethods(['getData', 'hasData', 'setData']) + ->setMethods(['hasData', 'getId']) ->disableOriginalConstructor() ->getMock(); $product->expects($this->once())->method('hasData')->with($configurableAttributes)->willReturn(false); + $product->expects($this->once())->method('getId')->willReturn(null); + + $this->assertEquals([], $this->model->getConfigurableAttributes($product)); + } + + public function testGetConfigurableAttributes() + { + $configurableAttributes = '_cache_instance_configurable_attributes'; + + /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */ + $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->setMethods(['getData', 'hasData', 'setData', 'getId']) + ->disableOriginalConstructor() + ->getMock(); + + $product->expects($this->once())->method('hasData')->with($configurableAttributes)->willReturn(false); + $product->expects($this->once())->method('getId')->willReturn(1); $attributeCollection = $this->getMockBuilder(Collection::class) ->setMethods(['setProductFilter', 'orderByPosition', 'load']) @@ -582,8 +592,7 @@ public function testHasOptionsConfigurableAttribute() ->disableOriginalConstructor() ->getMock(); $attributeMock = $this->getMockBuilder( - \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class - ) + \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class) ->disableOriginalConstructor() ->getMock(); From cbd6203d6505c5e366928dea5249b926a6a8bbb3 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 13 Nov 2018 14:27:31 +0200 Subject: [PATCH 0650/1158] GraphQl-222: Apply changes from CR for PR 162 Fix static tests --- .../GraphQl/Exception/GraphQlAuthorizationException.php | 4 ++-- .../Framework/GraphQl/Exception/GraphQlInputException.php | 4 ++-- .../GraphQl/Exception/GraphQlNoSuchEntityException.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php index f71652edc63b3..f1232ebd4d14b 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlAuthorizationException.php @@ -37,7 +37,7 @@ public function __construct(Phrase $phrase, \Exception $cause = null, $code = 0, } /** - * {@inheritDoc} + * @inheritdoc */ public function isClientSafe() : bool { @@ -45,7 +45,7 @@ public function isClientSafe() : bool } /** - * {@inheritDoc} + * @inheritdoc */ public function getCategory() : string { diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlInputException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlInputException.php index 6f97f06261358..429b7c04b7475 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlInputException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlInputException.php @@ -37,7 +37,7 @@ public function __construct(Phrase $phrase, \Exception $cause = null, $code = 0, } /** - * {@inheritDoc} + * @inheritdoc */ public function isClientSafe() : bool { @@ -45,7 +45,7 @@ public function isClientSafe() : bool } /** - * {@inheritDoc} + * @inheritdoc */ public function getCategory() : string { diff --git a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php index 4bd24d6cfd4a7..2a0b9d3bc2eaa 100644 --- a/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php +++ b/lib/internal/Magento/Framework/GraphQl/Exception/GraphQlNoSuchEntityException.php @@ -37,7 +37,7 @@ public function __construct(Phrase $phrase, \Exception $cause = null, $code = 0, } /** - * {@inheritDoc} + * @inheritdoc */ public function isClientSafe() : bool { @@ -45,7 +45,7 @@ public function isClientSafe() : bool } /** - * {@inheritDoc} + * @inheritdoc */ public function getCategory() : string { From 6062a1eae3d1ced249379daf4c77de711410b349 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 13 Nov 2018 14:34:53 +0200 Subject: [PATCH 0651/1158] GraphQl: Missed PHPDoc argument headers in method graphQlQuery --- .../Magento/TestFramework/TestCase/GraphQlAbstract.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php index 9754a340900e2..790581c476da1 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php @@ -52,11 +52,14 @@ public function graphQlQuery( } /** + * Compose headers + * + * @param array $headers * @return string[] */ - private function composeHeaders($headers) + private function composeHeaders(array $headers): array { - $headersArray =[]; + $headersArray = []; foreach ($headers as $key => $value) { $headersArray[] = sprintf('%s: %s', $key, $value); } From 74fce4acb449bb2f3b31e4e93d876654c5f0f0ea Mon Sep 17 00:00:00 2001 From: Vlad Veselov Date: Tue, 13 Nov 2018 14:50:30 +0200 Subject: [PATCH 0652/1158] Fix PHP Notice due to magento/magento2#18727 --- pub/index.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pub/index.php b/pub/index.php index 90b4778265447..d363951691d58 100644 --- a/pub/index.php +++ b/pub/index.php @@ -25,15 +25,14 @@ } $params = $_SERVER; -$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = array_replace_recursive( - $params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS], - [ +$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = + ($params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] ?? []) + + [ DirectoryList::PUB => [DirectoryList::URL_PATH => ''], DirectoryList::MEDIA => [DirectoryList::URL_PATH => 'media'], DirectoryList::STATIC_VIEW => [DirectoryList::URL_PATH => 'static'], DirectoryList::UPLOAD => [DirectoryList::URL_PATH => 'media/upload'], - ] -); + ]; $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params); /** @var \Magento\Framework\App\Http $app */ $app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); From 1378ed33cad3ab8fb4d121b700bfe53d8733c408 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 13 Nov 2018 15:11:50 +0200 Subject: [PATCH 0653/1158] GraphQl-11: Alphabetize Schema Fields -- Fix static tests --- .../Magento/Framework/GraphQl/Config/GraphQlReaderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php b/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php index 3d3372429123a..7f8996daa6e97 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php @@ -194,7 +194,7 @@ enumValues(includeDeprecated: true) { $sortFields = ['inputFields', 'fields']; foreach ($sortFields as $sortField) { isset($searchTerm[$sortField]) && is_array($searchTerm[$sortField]) - ? usort($searchTerm[$sortField], function($a, $b) { + ? usort($searchTerm[$sortField], function ($a, $b) { $cmpField = 'name'; return isset($a[$cmpField]) && isset($b[$cmpField]) ? strcmp($a[$cmpField], $b[$cmpField]) : 0; From 7f61b6f9d20565d0338cd1f0a39afde7b9edaabd Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 13 Nov 2018 15:39:59 +0200 Subject: [PATCH 0654/1158] GraphQl-222: Apply changes from CR for PR 162 - Fix API-functional tests --- .../GraphQl/Customer/AccountInformationTest.php | 2 +- .../GraphQl/Customer/RevokeCustomerTokenTest.php | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/AccountInformationTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/AccountInformationTest.php index 2caee84ba6f00..942e321a78718 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/AccountInformationTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/AccountInformationTest.php @@ -238,7 +238,7 @@ public function testUpdateAccountInformationIfCustomerIsLocked() /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * @expectedException \Exception - * @expectedExceptionMessage For changing "email" you should provide current "password". + * @expectedExceptionMessage Provide the current "password" to change "email". */ public function testUpdateEmailIfPasswordIsMissed() { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php index 415a81f8cf45a..9bdbf3059eeaf 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php @@ -23,7 +23,9 @@ public function testRevokeCustomerTokenValidCredentials() { $query = << 'Bearer ' . $customerToken]; $response = $this->graphQlQuery($query, [], '', $headerMap); - $this->assertTrue($response['revokeCustomerToken']); + $this->assertTrue($response['revokeCustomerToken']['result']); } /** @@ -46,7 +48,9 @@ public function testRevokeCustomerTokenForGuestCustomer() { $query = <<graphQlQuery($query, [], ''); From ee582ece43fada77f434f14c542e508ba5e7e68a Mon Sep 17 00:00:00 2001 From: Yevhen Sentiabov Date: Tue, 13 Nov 2018 15:53:41 +0200 Subject: [PATCH 0655/1158] MAGETWO-96291: Cannot proceed to Braintree PayPal from iPhone - Fixed `Place Order` action to prevent pop-up blocking --- .../js/view/payment/method-renderer/paypal.js | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) 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 abf434bc6da26..eaebd8492b0a1 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 @@ -7,7 +7,6 @@ define([ 'jquery', 'underscore', - 'mage/utils/wrapper', 'Magento_Checkout/js/view/payment/default', 'Magento_Braintree/js/view/payment/adapter', 'Magento_Checkout/js/model/quote', @@ -19,7 +18,6 @@ define([ ], function ( $, _, - wrapper, Component, Braintree, quote, @@ -105,6 +103,12 @@ define([ } }); + quote.shippingAddress.subscribe(function () { + if (self.isActive()) { + self.reInitPayPal(); + } + }); + // for each component initialization need update property this.isReviewRequired(false); this.initClientConfig(); @@ -222,9 +226,8 @@ define([ /** * Re-init PayPal Auth Flow - * @param {Function} callback - Optional callback */ - reInitPayPal: function (callback) { + reInitPayPal: function () { if (Braintree.checkout) { Braintree.checkout.teardown(function () { Braintree.checkout = null; @@ -235,17 +238,6 @@ define([ this.clientConfig.paypal.amount = this.grandTotalAmount; this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress(); - if (callback) { - this.clientConfig.onReady = wrapper.wrap( - this.clientConfig.onReady, - function (original, checkout) { - this.clientConfig.onReady = original; - original(checkout); - callback(); - }.bind(this) - ); - } - Braintree.setConfig(this.clientConfig); Braintree.setup(); }, @@ -428,19 +420,17 @@ define([ * Triggers when customer click "Continue to PayPal" button */ payWithPayPal: function () { - this.reInitPayPal(function () { - if (!additionalValidators.validate()) { - return; - } + if (!additionalValidators.validate()) { + return; + } - try { - Braintree.checkout.paypal.initAuthFlow(); - } catch (e) { - this.messageContainer.addErrorMessage({ - message: $t('Payment ' + this.getTitle() + ' can\'t be initialized.') - }); - } - }.bind(this)); + try { + Braintree.checkout.paypal.initAuthFlow(); + } catch (e) { + this.messageContainer.addErrorMessage({ + message: $t('Payment ' + this.getTitle() + ' can\'t be initialized.') + }); + } }, /** From 7dba16ba0d61af22b241d58d99f026d0a140222f Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 13 Nov 2018 15:55:47 +0200 Subject: [PATCH 0656/1158] GraphQl-39: Manage Shipping methods on Cart --- .../Address/AddressDataProvider.php | 2 +- .../{CartAddress.php => CartAddresses.php} | 24 ++----------------- .../Magento/QuoteGraphQl/etc/schema.graphqls | 2 +- 3 files changed, 4 insertions(+), 24 deletions(-) rename app/code/Magento/QuoteGraphQl/Model/{Resolver => Cart}/Address/AddressDataProvider.php (98%) rename app/code/Magento/QuoteGraphQl/Model/Resolver/{CartAddress.php => CartAddresses.php} (59%) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php b/app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php similarity index 98% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php rename to app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php index 80fe973c4e449..fb742477ec99b 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Address/AddressDataProvider.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/Address/AddressDataProvider.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\Address; +namespace Magento\QuoteGraphQl\Model\Cart\Address; use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Quote\Api\Data\AddressInterface; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php similarity index 59% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php rename to app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php index 54bd8fa2a5717..69544672bf12e 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddress.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartAddresses.php @@ -11,14 +11,12 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Api\CartRepositoryInterface; -use Magento\Quote\Model\MaskedQuoteIdToQuoteId; -use Magento\QuoteGraphQl\Model\Resolver\Address\AddressDataProvider; +use Magento\QuoteGraphQl\Model\Cart\Address\AddressDataProvider; /** * @inheritdoc */ -class CartAddress implements ResolverInterface +class CartAddresses implements ResolverInterface { /** * @var AddressDataProvider @@ -26,29 +24,11 @@ class CartAddress implements ResolverInterface private $addressDataProvider; /** - * @var CartRepositoryInterface - */ - private $cartRepository; - - /** - * @var MaskedQuoteIdToQuoteId - */ - private $maskedQuoteIdToQuoteId; - - /** - * CartAddress constructor. - * - * @param MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId - * @param CartRepositoryInterface $cartRepository * @param AddressDataProvider $addressDataProvider */ public function __construct( - MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId, - CartRepositoryInterface $cartRepository, AddressDataProvider $addressDataProvider ) { - $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->cartRepository = $cartRepository; $this->addressDataProvider = $addressDataProvider; } diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index ce982952f1aee..a6c56318d7a9a 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -95,7 +95,7 @@ type Cart { cart_id: String items: [CartItemInterface] applied_coupon: AppliedCoupon - addresses: [CartAddress]! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartAddress") + addresses: [CartAddress]! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartAddresses") } type CartAddress { From 4a8720485da929caa4301fdac430f91a3628d42d Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 13 Nov 2018 16:18:08 +0200 Subject: [PATCH 0657/1158] GraphQl-39: Manage Shipping methods on Cart - Fix static tests --- .../Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php index 7f945dca2fd76..a630b2d07c7df 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingMethodOnCart.php @@ -98,4 +98,4 @@ public function execute(Quote $cart, int $cartAddressId, string $carrierCode, st throw new GraphQlInputException(__($exception->getMessage())); } } -} \ No newline at end of file +} From 889824ea3bedd2295678d4bd631473a82105ae68 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Tue, 13 Nov 2018 15:31:05 +0100 Subject: [PATCH 0658/1158] Increased allowed query complexity to 300 --- app/code/Magento/GraphQl/etc/di.xml | 2 +- .../Framework/QueryComplexityLimiterTest.php | 63 ++++++++++++++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index 914dcc78e49e1..b2083ea758e56 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -100,7 +100,7 @@ 20 - 250 + 300 diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php index 9bf223068e226..352947714360a 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -263,6 +263,66 @@ public function testQueryComplexityIsLimited() percentage_value website_id } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } new_to_date new_from_date tier_price @@ -330,10 +390,9 @@ public function testQueryComplexityIsLimited() } } } - QUERY; - self::expectExceptionMessageRegExp('/Max query complexity should be 250 but got 252/'); + self::expectExceptionMessageRegExp('/Max query complexity should be 300 but got 302/'); $this->graphQlQuery($query); } From d84929a4241776521322ba3fc9521544639bd59c Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Tue, 13 Nov 2018 17:10:23 +0200 Subject: [PATCH 0659/1158] Fixed code style issue --- .../Test/Unit/Observer/CheckUserLoginBackendObserverTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php index 2d0a2a7e1c99a..415f022a7364d 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserLoginBackendObserverTest.php @@ -107,7 +107,6 @@ public function requiredCaptchaDataProvider(): array ]; } - /** * Test check user login in backend with wrong captcha * From 770e0f84c8ef2965f71b732bd2d38c529a4ff442 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich Date: Tue, 13 Nov 2018 18:23:00 +0300 Subject: [PATCH 0660/1158] MAGETWO-62728: My Wishlist - quantity input box issue - Fexed DOC section for add-to-wishlist.js file; --- .../Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js index db5f77348b2c0..8a20d2925849a 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js @@ -188,7 +188,7 @@ define([ /** * Bind form submit. * - @param {boolean} isFileUploaded + * @param {boolean} isFileUploaded */ bindFormSubmit: function (isFileUploaded) { var self = this; From 6afe3938708a4c166dfab30e60f7793e1b236963 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Tue, 13 Nov 2018 09:36:53 -0600 Subject: [PATCH 0661/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Added test for admin grid --- .../Test/AdminGroupedProductsListTest.xml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml new file mode 100644 index 0000000000000..b59cf1e2175d8 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml @@ -0,0 +1,73 @@ + + + + + + + + + + <description value="Products in group should show in admin list even when they are out of stock"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-93181"/> + <group value="GroupedProduct"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="category1"/> + <createData entity="SimpleProduct" stepKey="simpleProduct1"> + <requiredEntity createDataKey="category1"/> + </createData> + <!--Out of Stock--> + <createData entity="SimpleProduct4" stepKey="simpleProduct2"> + <requiredEntity createDataKey="category1"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <deleteData createDataKey="category1" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageAdd"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProductPage"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <actionGroup ref="fillGroupedProductForm" stepKey="fillMainProductForm"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <!-- Add two simple products to grouped product --> + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToSection"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductSection"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/> + <waitForElementVisible selector="{{AdminAddProductsToGroupPanel.filters}}" stepKey="waitForFilter"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku1"> + <argument name="product" value="$$simpleProduct1$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToGroupPanel.firstCheckbox}}" stepKey="checkOption1"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku2"> + <argument name="product" value="$$simpleProduct2$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToGroupPanel.firstCheckbox}}" stepKey="checkOption2"/> + <click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="addSelectedProducts"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + + <!-- Save product --> + <actionGroup ref="saveProductForm" stepKey="saveProductForm"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToProducts"/> + + <waitForText userInput="$$simpleProduct1.name$$" stepKey="assertProductIsInTheList"/> + <waitForText userInput="$$simpleProduct2.name$$" stepKey="assertProduct2IsInTheList"/> + </test> +</tests> From 1cb7ad9ec01b3735485e8edbe298a535c600f1ca Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Tue, 13 Nov 2018 09:39:57 -0600 Subject: [PATCH 0662/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Static fixed --- .../Magento/Catalog/Controller/Adminhtml/Category/Index.php | 4 +++- .../Magento/GroupedProduct/Model/Product/Type/Grouped.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php index 47969a4eca9ec..a5be6223bee75 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php @@ -7,8 +7,10 @@ namespace Magento\Catalog\Controller\Adminhtml\Category; use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; -use Magento\Framework\Url\EncoderInterface; +/** + * Controller for category listing + */ class Index extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface { /** diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index e54cb79b7b4e7..2f8249397819a 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -230,7 +230,7 @@ public function getAssociatedProducts($product, bool $includeOutOfStock = true) ); if (!$includeOutOfStock) { - $this->stockHelper->addIsInStockFilterToCollection($collection); + $this->stockHelper->addIsInStockFilterToCollection($collection); } foreach ($collection as $item) { From 9c9581306d7c92751f643101e482ab4e9e4a02fd Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Tue, 13 Nov 2018 16:40:54 +0100 Subject: [PATCH 0663/1158] Fixed travis test running condition --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 78b088c9d848d..bd2b94865cafd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,6 +64,6 @@ script: # The scripts for grunt/phpunit type tests - if [ $TEST_SUITE == "functional" ]; then dev/tests/functional/vendor/phpunit/phpunit/phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js"] && [ $TEST_SUITE != "api" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi + - if [ $TEST_SUITE != "functional" ] && [ $TEST_SUITE != "js"] && [ $TEST_SUITE != "graphql-api-functional" ]; then phpunit -c dev/tests/$TEST_SUITE $TEST_FILTER; fi - if [ $TEST_SUITE == "js" ]; then grunt $GRUNT_COMMAND; fi - if [ $TEST_SUITE == "graphql-api-functional" ]; then phpunit -c dev/tests/api-functional; fi From a0f675dd403348a52ee7f64176a75df74325f627 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Tue, 13 Nov 2018 18:50:07 +0300 Subject: [PATCH 0664/1158] MAGETWO-95809: Item row total display incorrect value in API response - Fix static test --- app/code/Magento/Sales/Plugin/DataObjectProcessor.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Plugin/DataObjectProcessor.php b/app/code/Magento/Sales/Plugin/DataObjectProcessor.php index 5c61cdda9efc2..2ebf0364c86a3 100644 --- a/app/code/Magento/Sales/Plugin/DataObjectProcessor.php +++ b/app/code/Magento/Sales/Plugin/DataObjectProcessor.php @@ -10,7 +10,7 @@ use Magento\Framework\Reflection\DataObjectProcessor as Subject; use Magento\Sales\Api\Data\OrderItemInterface; use Magento\Sales\Model\Order\Item as OrderItem; -use Magento\Weee\Block\Item\Price\Renderer; +use Magento\Sales\Block\Adminhtml\Items\Column\DefaultColumn; /** * Class for changing row total in response. @@ -18,15 +18,15 @@ class DataObjectProcessor { /** - * @var Renderer + * @var DefaultColumn */ private $priceRenderer; /** - * @param Renderer $priceRenderer + * @param DefaultColumn $priceRenderer */ public function __construct( - Renderer $priceRenderer + DefaultColumn $priceRenderer ) { $this->priceRenderer = $priceRenderer; } From 1b21f6fd18a1ef3afe9f8a17949131b5b606b5eb Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Tue, 13 Nov 2018 18:08:30 +0200 Subject: [PATCH 0665/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - change test according to specific of B2B elements --- ...thOnlinePaymentIncludingTaxAndDiscount.xml | 24 ++++++++++++++----- .../AdminCreateCartPriceRuleActionGroup.xml | 18 -------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml index fe1ed76e77f70..d1d685effd133 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CretateAdminOrderWithOnlinePaymentIncludingTaxAndDiscount.xml @@ -70,8 +70,21 @@ <actionGroup ref="logout" stepKey="logout"/> </after> - <!-- Create a cart price rule for Fixed amount discount for whole cart --> - <actionGroup ref="AdminCreateCartPriceRuleForRetailerActionGroup" stepKey="createCartPriceRule"/> + <!-- Create a cart price rule with 10% discount for whole cart --> + <click selector="{{AdminMenuSection.marketing}}" stepKey="clickOnMarketing" /> + <waitForPageLoad stepKey="waitForMarketing" time="3"/> + <click selector="{{CartPriceRulesSubmenuSection.cartPriceRules}}" stepKey="clickOnCartPriceRules"/> + <waitForPageLoad stepKey="waitForCartPriceRules" time="3"/> + <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRule"/> + <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{SimpleSalesRule.name}}" stepKey="fillRuleName"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="selectWebsites"/> + <actionGroup ref="selectRetailerCustomerGroup" stepKey="selectRetailerCustomerGroup"/> + <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Percent of product price discount" stepKey="selectActionType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="10" stepKey="fillDiscountAmount"/> + <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> + <waitForPageLoad stepKey="waitForCartRuleLoad" time="3"/> + <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> <!--Set Taxable Goods for Shipping Tax Class--> <actionGroup ref="changeShippingTaxClass" stepKey="changeShippingTaxClass"/> @@ -100,15 +113,14 @@ <!--Submit Order--> <click stepKey="submitOrder" selector="{{NewOrderSection.submitOrder}}"/> <waitForPageLoad stepKey="waitForSubmitOrder" time="5"/> - <see selector="{{NewOrderSection.successMessage}}" userInput="You created the order." stepKey="seeNewOrder" after="waitForSubmitOrder"/> - + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeOrderSuccessMessage" after="waitForSubmitOrder"/> <!-- Create New invoice--> <actionGroup ref="adminFastCreateInvoice" stepKey="createInvoice"/> - <!--Get access to Credit Memo page from Invocie page--> + <!--Get access to Credit Memo page from Invoice page--> <click selector="{{AdminInvoiceMainActionsSection.openNewCreditMemoFromInvoice}}" stepKey="clickCreateNewCreditMemo"/> <waitForPageLoad stepKey="waitForLoadNewCreditMemoPage" time="5"/> - <see selector="{{AdminCreditMemoOrderInformationSection.orderId}}" userInput="New Memo for" stepKey="seeNewCreditMemo" after="waitForLoadNewCreditMemoPage"/> + <see selector="{{AdminCreditMemoOrderInformationSection.orderStatus}}" userInput="Processing" stepKey="seeNewCreditMemo"/> </test> </tests> \ No newline at end of file diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml index 6a837577ece3d..6ee7b556beb7d 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml @@ -24,24 +24,6 @@ <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> </actionGroup> - <!--Create Cart price Rule for Retailer customer--> - <actionGroup name="AdminCreateCartPriceRuleForRetailerActionGroup"> - <click selector="{{AdminMenuSection.marketing}}" stepKey="clickOnMarketing" /> - <waitForPageLoad stepKey="waitForMarketing" time="3"/> - <click selector="{{CartPriceRulesSubmenuSection.cartPriceRules}}" stepKey="clickOnCartPriceRules"/> - <waitForPageLoad stepKey="waitForCartPriceRules" time="5"/> - <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRule"/> - <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{SimpleSalesRule.name}}" stepKey="fillRuleName"/> - <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="selectWebsites"/> - <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="Retailer" stepKey="selectCustomerGroup"/> - <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> - <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Percent of product price discount" stepKey="selectActionType"/> - <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="10" stepKey="fillDiscountAmount"/> - <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> - <waitForPageLoad stepKey="waitForCartRuleLoad" time="5"/> - <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> - </actionGroup> - <!--Delete Cart price Rule for Retailer customer--> <actionGroup name="AdminDeleteCartPriceRuleForRetailerActionGroup"> <click selector="{{AdminMenuSection.marketing}}" stepKey="clickOnMarketing" /> From 702353a0f32bc0b5d7cca708c90ec1839c983a8e Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Tue, 13 Nov 2018 10:12:17 -0600 Subject: [PATCH 0666/1158] MAGETWO-95589: [FT][Temando] Tests fail with enabled Temando extension --- .../Test/Mftf/Section/CheckoutShippingMethodsSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml index 56ed42fbfbbea..ab4b59fd67d03 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml @@ -13,6 +13,7 @@ <element name="firstShippingMethod" type="radio" selector="//*[@id='checkout-shipping-method-load']//input[@class='radio']"/> <element name="shippingMethodRow" type="text" selector=".form.methods-shipping table tbody tr"/> <element name="checkShippingMethodByName" type="radio" selector="//div[@id='checkout-shipping-method-load']//td[contains(., '{{var1}}')]/..//input" parameterized="true"/> + <element name="shippingMethodFlatRate" type="radio" selector="#checkout-shipping-method-load input[value='flatrate_flatrate']"/> <element name="shippingMethodRowByName" type="text" selector="//div[@id='checkout-shipping-method-load']//td[contains(., '{{var1}}')]/.." parameterized="true"/> <element name="shipHereButton" type="button" selector="//div/following-sibling::div/button[contains(@class, 'action-select-shipping-item')]"/> <element name="shippingMethodLoader" type="button" selector="//div[contains(@class, 'checkout-shipping-method')]/following-sibling::div[contains(@class, 'loading-mask')]"/> From 534da46ce569e8fd4c079bc5978c1959cb45f06c Mon Sep 17 00:00:00 2001 From: Sergii Ivashchenko <serg.ivashchenko@gmail.com> Date: Tue, 13 Nov 2018 18:18:29 +0200 Subject: [PATCH 0667/1158] Travis integration tests timeout fix --- dev/travis/before_script.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index dbd9d1cd4fec1..20bc59d718f13 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -13,9 +13,9 @@ case $TEST_SUITE in test_set_list=$(find testsuite/* -maxdepth 1 -mindepth 1 -type d | sort) test_set_count=$(printf "$test_set_list" | wc -l) - test_set_size[1]=$(printf "%.0f" $(echo "$test_set_count*0.17" | bc)) #17% - test_set_size[2]=$(printf "%.0f" $(echo "$test_set_count*0.27" | bc)) #27% - test_set_size[3]=$((test_set_count-test_set_size[1]-test_set_size[2])) #56% + test_set_size[1]=$(printf "%.0f" $(echo "$test_set_count*0.13" | bc)) #13% + test_set_size[2]=$(printf "%.0f" $(echo "$test_set_count*0.30" | bc)) #30% + test_set_size[3]=$((test_set_count-test_set_size[1]-test_set_size[2])) #55% echo "Total = ${test_set_count}; Batch #1 = ${test_set_size[1]}; Batch #2 = ${test_set_size[2]}; Batch #3 = ${test_set_size[3]};"; echo "==> preparing integration testsuite on index $INTEGRATION_INDEX with set size of ${test_set_size[$INTEGRATION_INDEX]}" From afd128e53d475092d8fbdf0c2a65d9654fbef9a6 Mon Sep 17 00:00:00 2001 From: vitaliyboyko <v.boyko@atwix.com> Date: Tue, 13 Nov 2018 18:27:09 +0200 Subject: [PATCH 0668/1158] graphQl: removed redundant multishipping references --- .../Magento/QuoteGraphQl/etc/graphql/di.xml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml index e7417d657a0ea..86bc954ae4ac4 100644 --- a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml @@ -8,21 +8,4 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressesOnCartInterface" type="Magento\QuoteGraphQl\Model\Cart\SetShippingAddressOnCart" /> - <virtualType name="multishippingPaymentSpecification" type="Magento\Payment\Model\Method\Specification\Composite"> - <arguments> - <argument name="specifications" xsi:type="array"> - <item name="enabled" xsi:type="string">Magento\Multishipping\Model\Payment\Method\Specification\Enabled</item> - </argument> - </arguments> - </virtualType> - <type name="Magento\Multishipping\Block\Checkout\Billing"> - <arguments> - <argument name="paymentSpecification" xsi:type="object">multishippingPaymentSpecification</argument> - </arguments> - </type> - <type name="Magento\Multishipping\Model\Checkout\Type\Multishipping"> - <arguments> - <argument name="paymentSpecification" xsi:type="object">multishippingPaymentSpecification</argument> - </arguments> - </type> </config> From c9b52500a52067b8ccfc3329b7456512b6520526 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Tue, 13 Nov 2018 18:37:09 +0200 Subject: [PATCH 0669/1158] Fixing the customer subscribing from different stores --- .../Model/Plugin/CustomerPlugin.php | 18 ++++++++++--- .../Unit/Model/Plugin/CustomerPluginTest.php | 25 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php index 22b31575debbc..f7467ef07aadb 100644 --- a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php +++ b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php @@ -6,11 +6,13 @@ namespace Magento\Newsletter\Model\Plugin; use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository; +use Magento\Customer\Api\Data\CustomerExtensionInterface; use Magento\Customer\Api\Data\CustomerInterface; -use Magento\Newsletter\Model\SubscriberFactory; use Magento\Framework\Api\ExtensionAttributesFactory; +use Magento\Framework\App\ObjectManager; use Magento\Newsletter\Model\ResourceModel\Subscriber; -use Magento\Customer\Api\Data\CustomerExtensionInterface; +use Magento\Newsletter\Model\SubscriberFactory; +use Magento\Store\Model\StoreManagerInterface; class CustomerPlugin { @@ -36,21 +38,29 @@ class CustomerPlugin */ private $customerSubscriptionStatus = []; + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * Initialize dependencies. * * @param SubscriberFactory $subscriberFactory * @param ExtensionAttributesFactory $extensionFactory * @param Subscriber $subscriberResource + * @param StoreManagerInterface|null $storeManager */ public function __construct( SubscriberFactory $subscriberFactory, ExtensionAttributesFactory $extensionFactory, - Subscriber $subscriberResource + Subscriber $subscriberResource, + StoreManagerInterface $storeManager = null ) { $this->subscriberFactory = $subscriberFactory; $this->extensionFactory = $extensionFactory; $this->subscriberResource = $subscriberResource; + $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); } /** @@ -155,6 +165,8 @@ public function afterGetById(CustomerRepository $subject, CustomerInterface $cus if ($extensionAttributes === null) { /** @var CustomerExtensionInterface $extensionAttributes */ $extensionAttributes = $this->extensionFactory->create(CustomerInterface::class); + $storeId = $this->storeManager->getStore()->getId(); + $customer->setStoreId($storeId); $customer->setExtensionAttributes($extensionAttributes); } if ($extensionAttributes->getIsSubscribed() === null) { diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php index e809b7e37a432..3be28cacc93e0 100644 --- a/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php +++ b/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php @@ -10,6 +10,8 @@ use Magento\Customer\Api\Data\CustomerExtensionInterface; use Magento\Framework\Api\ExtensionAttributesFactory; use Magento\Newsletter\Model\ResourceModel\Subscriber; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; class CustomerPluginTest extends \PHPUnit\Framework\TestCase { @@ -53,6 +55,11 @@ class CustomerPluginTest extends \PHPUnit\Framework\TestCase */ private $customerMock; + /** + * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManagerMock; + protected function setUp() { $this->subscriberFactory = $this->getMockBuilder(\Magento\Newsletter\Model\SubscriberFactory::class) @@ -87,6 +94,8 @@ protected function setUp() ->setMethods(['getExtensionAttributes']) ->disableOriginalConstructor() ->getMockForAbstractClass(); + $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); + $this->subscriberFactory->expects($this->any())->method('create')->willReturn($this->subscriber); $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -96,6 +105,7 @@ protected function setUp() 'subscriberFactory' => $this->subscriberFactory, 'extensionFactory' => $this->extensionFactoryMock, 'subscriberResource' => $this->subscriberResourceMock, + 'storeManager' => $this->storeManagerMock, ] ); } @@ -206,6 +216,7 @@ public function testAfterGetByIdCreatesExtensionAttributesIfItIsNotSet( ) { $subject = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); $subscriber = [$subscriberStatusKey => $subscriberStatusValue]; + $this->prepareStoreData(); $this->extensionFactoryMock->expects($this->any()) ->method('create') @@ -233,6 +244,7 @@ public function testAfterGetByIdSetsIsSubscribedFlagIfItIsNotSet() { $subject = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); $subscriber = ['subscriber_id' => 1, 'subscriber_status' => 1]; + $this->prepareStoreData(); $this->customerMock->expects($this->any()) ->method('getExtensionAttributes') @@ -267,4 +279,17 @@ public function afterGetByIdDataProvider() [null, null, false], ]; } + + /** + * Prepare store information + * + * @return void + */ + private function prepareStoreData() + { + $storeId = 1; + $storeMock = $this->createMock(Store::class); + $storeMock->expects($this->any())->method('getId')->willReturn($storeId); + $this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock); + } } From 54139e30a538312077526f44052abe85b3b17c49 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Mon, 12 Nov 2018 16:43:02 -0600 Subject: [PATCH 0670/1158] MAGETWO-96262: Order with simple product after partial cancellation and credit memo has status 'Processing' --- app/code/Magento/Sales/Model/Order.php | 7 +- app/code/Magento/Sales/Model/Order/Item.php | 2 +- .../ActionGroup/AdminOrderActionGroup.xml | 18 -- ...inAbleToShipPartiallyInvoicedItemsTest.xml | 168 ------------------ .../Sales/Test/Unit/Model/Order/ItemTest.php | 8 +- .../Sales/Test/Unit/Model/OrderTest.php | 165 ----------------- .../Section/AdminShipmentItemsSection.xml | 1 - .../Service/V1/CreditMemoCreateRefundTest.php | 3 +- .../Sales/Service/V1/RefundOrderTest.php | 5 +- .../Test/TestCase/MassOrdersUpdateTest.xml | 2 +- .../Magento/Paypal/Model/IpnTest.php | 6 +- 11 files changed, 12 insertions(+), 373 deletions(-) delete mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index ca8063aa57884..6fed435773eaa 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -547,12 +547,7 @@ public function canCancel() } } - $allRefunded = true; - foreach ($this->getAllItems() as $orderItem) { - $allRefunded = $allRefunded && ((float)$orderItem->getQtyRefunded() == (float)$orderItem->getQtyInvoiced()); - } - - if ($allInvoiced && !$allRefunded) { + if ($allInvoiced) { return false; } diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php index cc8bb7aae780c..4bd856e85433d 100644 --- a/app/code/Magento/Sales/Model/Order/Item.php +++ b/app/code/Magento/Sales/Model/Order/Item.php @@ -232,7 +232,7 @@ public function getQtyToShip() */ public function getSimpleQtyToShip() { - $qty = $this->getQtyOrdered() - $this->getQtyShipped() - $this->getQtyCanceled(); + $qty = $this->getQtyOrdered() - $this->getQtyShipped() - $this->getQtyRefunded() - $this->getQtyCanceled(); return max(round($qty, 8), 0); } diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index a26fd6bc1c3a7..c82623632d782 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -94,24 +94,6 @@ <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> </actionGroup> - <!--Add a simple product to order with user defined quantity--> - <actionGroup name="addSimpleProductToOrderWithCustomQuantity"> - <arguments> - <argument name="product" defaultValue="_defaultProduct"/> - <argument name="quantity" type="string"/> - </arguments> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMastToDisappear"/> - <waitForElementVisible selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="waitForAddProductButton"/> - <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> - <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilter"/> - <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearch"/> - <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> - <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> - <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="{{quantity}}" stepKey="fillProductQty"/> - <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> - <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> - </actionGroup> - <!--Add configurable product to order --> <actionGroup name="addConfigurableProductToOrder"> <arguments> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml deleted file mode 100644 index e4fd894f608c5..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ /dev/null @@ -1,168 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminAbleToShipPartiallyInvoicedItemsTest"> - <annotations> - <title value="Ship Action is available for remaining of the partially invoiced items "/> - <description value="Admin should be able to ship remaining ordered items if some of them are already refunded"/> - <severity value="CRITICAL"/> - <testCaseId value="MAGETWO-93030"/> - <group value="sales"/> - - </annotations> - <before> - <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="_defaultProduct" stepKey="createSimpleProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - </before> - <after> - <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> - <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> - </after> - - <!--login to Admin--> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> - <comment userInput="Admin creates order" stepKey="adminCreateOrderComment"/> - <amOnPage url="{{AdminOrdersPage.url}}" stepKey="navigateToOrderIndexPage"/> - <waitForPageLoad stepKey="waitForIndexPageLoad"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Orders" stepKey="seeIndexPageTitle"/> - - <!--Create new order--> - <click selector="{{AdminOrdersGridSection.createNewOrder}}" stepKey="clickCreateNewOrder"/> - <click selector="{{AdminOrderFormActionSection.CreateNewCustomer}}" stepKey="clickCreateCustomer"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Create New Order" stepKey="seeNewOrderPageTitle"/> - <actionGroup ref="addSimpleProductToOrderWithCustomQuantity" stepKey="addSimpleProductToOrderWithUserDefinedQty"> - <argument name="product" value="_defaultProduct"/> - <argument name="quantity" value="10"/> - </actionGroup> - - <!--Fill customer group and customer email which both are now required fields--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="addSimpleProductToOrderWithUserDefinedQty"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail" after="selectCustomerGroup"/> - - <!--Fill customer address information--> - <actionGroup ref="fillOrderCustomerInformation" stepKey="fillCustomerAddress" after="fillCustomerEmail"> - <argument name="customer" value="Simple_US_Customer"/> - <argument name="address" value="US_Address_TX"/> - </actionGroup> - <!-- Select shipping --> - <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping" after="fillCustomerAddress"/> - - <!--Verify totals on Order page--> - <see selector="{{AdminOrderFormTotalSection.total('Subtotal')}}" userInput="$1,230.00" stepKey="seeOrderSubTotal" after="selectFlatRateShipping"/> - <see selector="{{AdminOrderFormTotalSection.total('Shipping')}}" userInput="$50.00" stepKey="seeOrderShipping" after="seeOrderSubTotal"/> - <scrollTo selector="{{AdminOrderFormTotalSection.grandTotal}}" stepKey="scrollToOrderGrandTotal"/> - <see selector="{{AdminOrderFormTotalSection.grandTotal}}" userInput="$1,280.00" stepKey="seeCorrectGrandTotal" after="scrollToOrderGrandTotal"/> - - <!--Submit Order and verify information--> - <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder" after="seeCorrectGrandTotal"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskTodisappear"/> - <waitForPageLoad stepKey="waitForOrderToProcess"/> - <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPage" after="clickSubmitOrder"/> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeSuccessMessage" after="seeViewOrderPage"/> - <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId" after="seeSuccessMessage"/> - <scrollTo selector="{{AdminOrderItemsOrderedSection.qtyColumn}}" stepKey="scrollToItemsOrdered" after="getOrderId"/> - <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Ordered 10" stepKey="seeQtyOfItemsOrdered" after="scrollToItemsOrdered"/> - - <!--Create order invoice for first half of ordered items--> - <comment userInput="Admin creates invoice for order" stepKey="adminCreateInvoiceComment" /> - <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceActionButton"/> - <!--<seeInCurrentUrl url="{{AdminInvoiceNewPage.url}}" stepKey="seeOrderInvoiceUrl" after="clickInvoiceAction"/>--> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage" after="clickInvoiceActionButton"/> - <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced"/> - - <!--Verify items invoiced information--> - <fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="invoiceHalfTheItems"/> - <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQtyToBeInvoiced"/> - <waitForLoadingMaskToDisappear stepKey="WaitForQtyToUpdate"/> - <waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitforSubmitInvoiceBtn"/> - - <!--Submit Invoice--> - <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="submitInvoice"/> - <waitForLoadingMaskToDisappear stepKey="WaitForInvoiceToSubmit"/> - <!--<waitForElementVisible selector="{{AdminOrderDetailsMessagesSection.successMessage}}" stepKey="waitUntilInvoiceSucesssMsg"/>--> - - <!--Invoice created successfully--> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceSuccessMessage"/> - <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoicesTab"/> - <waitForLoadingMaskToDisappear stepKey="waitForInvoiceGridToLoad" after="clickInvoicesTab"/> - <see selector="{{AdminOrderInvoicesTabSection.gridRow('1')}}" userInput="$665.00" stepKey="seeOrderInvoiceTabInGrid" after="waitForInvoiceGridToLoad"/> - <click selector="{{AdminOrderInvoicesTabSection.viewGridRow('1')}}" stepKey="clickToViewInvoice" after="seeOrderInvoiceTabInGrid"/> - <click selector="{{AdminInvoiceOrderInformationSection.orderId}}" stepKey="clickOrderIdLinkOnInvoice"/> - - <!--Ship Order--> - <comment userInput="Admin creates shipment" stepKey="adminCreatesShipmentComment" before="clickShip"/> - <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShip" after="clickOrderIdLinkOnInvoice"/> - <seeInCurrentUrl url="{{AdminShipmentNewPage.url}}" stepKey="OrderShipmentUrl" after="clickShip"/> - <scrollTo selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" stepKey="scrollToItemsToShip"/> - <see selector="{{AdminShipmentItemsSection.itemQty('1')}}" userInput="Invoiced 5" stepKey="see5itemsInvoiced"/> - <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="5" stepKey="fillQtyOfItemsToShip"/> - - <!--Submit Shipment--> - <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="submitShipment" after="fillQtyOfItemsToShip"/> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="successfullShipmentCreation" after="submitShipment"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="$getOrderId" stepKey="seeOrderIdInPageTitleAfterShip"/> - - <!--Verify Items Status and Shipped Qty in the Items Ordered section--> - <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToItemsShipped"/> - <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 5" stepKey="see5itemsShipped"/> - - <!--Create Credit Memo--> - <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment"/> - <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreateCreditMemo" after="createCreditMemoComment"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> - - <!--Submit refund--> - <scrollTo selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" stepKey="scrollToItemsToRefund"/> - <!--<fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" stepKey="fillQtyOfItemsToRefund" after="scrollToItemsToRefund"/>--> - <!--<click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/>--> - <waitForLoadingMaskToDisappear stepKey="waitForRefundQtyToUpdate"/> - <waitForElementVisible selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="seeSubmitRefundBtn"/> - <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="submitRefundOffline"/> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccessMsg" after="submitRefundOffline"/> - - <!--Create invoice for rest of the ordered items--> - <comment userInput="Admin creates invoice for rest of the items" stepKey="adminCreateInvoiceComment2" /> - <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceActionForRestOfItems"/> - <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage2" after="clickInvoiceActionForRestOfItems"/> - - <comment userInput="Qty To Invoice is 5" stepKey="seeRemainderInQtyToInvoice"/> - <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced2"/> - <!--<see selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced2"/>--> - <seeInField userInput="5" selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="see5InTheQtyToInvoice"/> - - <!--Verify items invoiced information--> - <see selector="{{AdminInvoiceItemsSection.itemQty('1')}}" userInput="Refunded 5" stepKey="seeQtyOfItemsRefunded"/> - - <!--Submit Invoice--> - <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="submitInvoice2" /> - - <!--Invoice created successfully for the rest of the ordered items--> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceSuccessMessage2" after="submitInvoice2"/> - - <!--Verify Ship Action can be done for the rest of the invoiced items --> - <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipActionForRestOfItems" after="seeInvoiceSuccessMessage2"/> - - <!--Verify Items To Ship section --> - <scrollTo selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" stepKey="scrollToItemsToShip2"/> - <see selector="{{AdminShipmentItemsSection.itemQty('1')}}" userInput="Invoiced 10" stepKey="SeeAll10ItemsInvoiced"/> - <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="5" stepKey="fillRestOfItemsToShip"/> - - <!--Submit Shipment--> - <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="submitShipment2" after="fillRestOfItemsToShip"/> - <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="successfullyCreatedShipment" after="submitShipment2"/> - - <!--Verify Items Status and Shipped Qty in the Items Ordered section--> - <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToItemsOrdered2"/> - <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 10" stepKey="seeAllItemsShipped"/> - </test> -</tests> - diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php index 3d4a5785d6254..76bfd62a7b889 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php @@ -295,14 +295,14 @@ public function getItemQtyVariants() 'qty_ordered' => 12, 'qty_invoiced' => 5, 'qty_refunded' => 5, 'qty_shipped' => 0, 'qty_canceled' => 0, ], - 'expectedResult' => ['to_ship' => 12.0, 'to_invoice' => 7.0] + 'expectedResult' => ['to_ship' => 7.0, 'to_invoice' => 7.0] ], 'partially_refunded' => [ 'options' => [ 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 5, 'qty_shipped' => 0, 'qty_canceled' => 0, ], - 'expectedResult' => ['to_ship' => 12.0, 'to_invoice' => 0.0] + 'expectedResult' => ['to_ship' => 7.0, 'to_invoice' => 0.0] ], 'partially_shipped' => [ 'options' => [ @@ -316,7 +316,7 @@ public function getItemQtyVariants() 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 5, 'qty_shipped' => 4, 'qty_canceled' => 0 ], - 'expectedResult' => ['to_ship' => 8.0, 'to_invoice' => 0.0] + 'expectedResult' => ['to_ship' => 3.0, 'to_invoice' => 0.0] ], 'complete' => [ 'options' => [ @@ -337,7 +337,7 @@ public function getItemQtyVariants() 'qty_ordered' => 4.4, 'qty_invoiced' => 0.4, 'qty_refunded' => 0.4, 'qty_shipped' => 4, 'qty_canceled' => 0, ], - 'expectedResult' => ['to_ship' => 0.4, 'to_invoice' => 4.0] + 'expectedResult' => ['to_ship' => 0.0, 'to_invoice' => 4.0] ], 'completely_invoiced_using_decimals' => [ 'options' => [ diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 873cd64e9c364..4c76dab99efa5 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -117,8 +117,6 @@ protected function setUp() 'getQuoteItemId', 'getLockedDoInvoice', 'getProductId', - 'getQtyRefunded', - 'getQtyInvoiced', ]); $this->salesOrderCollectionMock = $this->getMockBuilder( \Magento\Sales\Model\ResourceModel\Order\Collection::class @@ -623,163 +621,6 @@ public function testCanCancelAllInvoiced() $this->item->expects($this->any()) ->method('getQtyToInvoice') ->willReturn(0); - $this->item->expects($this->any()) - ->method('getQtyRefunded') - ->willReturn(0); - $this->item->expects($this->any()) - ->method('getQtyInvoiced') - ->willReturn(1); - - $this->assertFalse($this->order->canCancel()); - } - - public function testCanCancelAllRefunded() - { - $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class) - ->disableOriginalConstructor() - ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp']) - ->getMock(); - $paymentMock->expects($this->any()) - ->method('canReviewPayment') - ->will($this->returnValue(false)); - $paymentMock->expects($this->any()) - ->method('canFetchTransactionInfo') - ->will($this->returnValue(false)); - $collectionMock = $this->createPartialMock( - \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, - ['getItems', 'setOrderFilter'] - ); - $this->orderItemCollectionFactoryMock->expects($this->any()) - ->method('create') - ->will($this->returnValue($collectionMock)); - $collectionMock->expects($this->any()) - ->method('setOrderFilter') - ->willReturnSelf(); - $this->preparePaymentMock($paymentMock); - - $this->prepareItemMock(0); - - $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); - $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); - - $this->item->expects($this->any()) - ->method('isDeleted') - ->willReturn(false); - $this->item->expects($this->any()) - ->method('getQtyToInvoice') - ->willReturn(0); - $this->item->expects($this->any()) - ->method('getQtyRefunded') - ->willReturn(10); - $this->item->expects($this->any()) - ->method('getQtyInvoiced') - ->willReturn(10); - - $this->assertTrue($this->order->canCancel()); - } - - /** - * Test that order can be canceled if some items were partially invoiced with certain qty - * and then refunded for this qty. - * Sample: - * - ordered qty = 20 - * - invoiced = 10 - * - refunded = 10 - */ - public function testCanCancelPartiallyInvoicedAndRefunded() - { - $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class) - ->disableOriginalConstructor() - ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp']) - ->getMock(); - $paymentMock->expects($this->any()) - ->method('canReviewPayment') - ->will($this->returnValue(false)); - $paymentMock->expects($this->any()) - ->method('canFetchTransactionInfo') - ->will($this->returnValue(false)); - $collectionMock = $this->createPartialMock( - \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, - ['getItems', 'setOrderFilter'] - ); - $this->orderItemCollectionFactoryMock->expects($this->any()) - ->method('create') - ->will($this->returnValue($collectionMock)); - $collectionMock->expects($this->any()) - ->method('setOrderFilter') - ->willReturnSelf(); - $this->preparePaymentMock($paymentMock); - - $this->prepareItemMock(0); - - $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); - $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); - - $this->item->expects($this->any()) - ->method('isDeleted') - ->willReturn(false); - $this->item->expects($this->any()) - ->method('getQtyToInvoice') - ->willReturn(10); - $this->item->expects($this->any()) - ->method('getQtyRefunded') - ->willReturn(10); - $this->item->expects($this->any()) - ->method('getQtyInvoiced') - ->willReturn(10); - - $this->assertTrue($this->order->canCancel()); - } - - /** - * Test that order CAN NOT be canceled if some items were partially invoiced with certain qty - * and then refunded for less than that qty. - * Sample: - * - ordered qty = 10 - * - invoiced = 10 - * - refunded = 5 - */ - public function testCanCancelPartiallyInvoicedAndNotFullyRefunded() - { - $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class) - ->disableOriginalConstructor() - ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp']) - ->getMock(); - $paymentMock->expects($this->any()) - ->method('canReviewPayment') - ->will($this->returnValue(false)); - $paymentMock->expects($this->any()) - ->method('canFetchTransactionInfo') - ->will($this->returnValue(false)); - $collectionMock = $this->createPartialMock( - \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, - ['getItems', 'setOrderFilter'] - ); - $this->orderItemCollectionFactoryMock->expects($this->any()) - ->method('create') - ->will($this->returnValue($collectionMock)); - $collectionMock->expects($this->any()) - ->method('setOrderFilter') - ->willReturnSelf(); - $this->preparePaymentMock($paymentMock); - - $this->prepareItemMock(0); - - $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); - $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); - - $this->item->expects($this->any()) - ->method('isDeleted') - ->willReturn(false); - $this->item->expects($this->any()) - ->method('getQtyToInvoice') - ->willReturn(0); - $this->item->expects($this->any()) - ->method('getQtyRefunded') - ->willReturn(5); - $this->item->expects($this->any()) - ->method('getQtyInvoiced') - ->willReturn(10); $this->assertFalse($this->order->canCancel()); } @@ -1243,9 +1084,6 @@ public function testGetCreatedAtFormattedUsesCorrectLocale() $this->order->getCreatedAtFormatted(\IntlDateFormatter::SHORT); } - /** - * @return array - */ public function notInvoicingStatesProvider() { return [ @@ -1255,9 +1093,6 @@ public function notInvoicingStatesProvider() ]; } - /** - * @return array - */ public function canNotCreditMemoStatesProvider() { return [ diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml index a7bf82588f7c7..9a7b3f1ff6bbf 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml @@ -12,7 +12,6 @@ <element name="itemName" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-product .product-title" parameterized="true"/> <element name="itemSku" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-product .product-sku-block" parameterized="true"/> <element name="itemQty" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-ordered-qty .qty-table" parameterized="true"/> - <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-qty input.qty-item" parameterized="true"/> <element name="nameColumn" type="text" selector=".order-shipment-table .col-product .product-title"/> <element name="skuColumn" type="text" selector=".order-shipment-table .col-product .product-sku-block"/> </section> diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php index eae0e600434a6..8262a7e41543e 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php @@ -115,8 +115,7 @@ public function testInvoke() ); $this->assertNotEmpty($result); $order = $this->objectManager->get(OrderRepositoryInterface::class)->get($order->getId()); - //Totally refunded orders still can be processed and shipped. - $this->assertEquals(Order::STATE_PROCESSING, $order->getState()); + $this->assertEquals(Order::STATE_CLOSED, $order->getState()); } private function getItemsForRest($order) diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php index aacda763ca2aa..12cbe1ca0e5e2 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php @@ -86,11 +86,10 @@ public function testShortRequest() 'Failed asserting that proper shipping amount of the Order was refunded' ); - //Totally refunded orders can be processed. - $this->assertEquals( + $this->assertNotEquals( $existingOrder->getStatus(), $updatedOrder->getStatus(), - 'Failed asserting that order status has not changed' + 'Failed asserting that order status was changed' ); } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { $this->fail('Failed asserting that Creditmemo was created'); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml index 31d5c30d25fc7..f59e6df845b6e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml @@ -22,7 +22,7 @@ <data name="steps" xsi:type="string">invoice, shipment|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Complete,Canceled</data> + <data name="resultStatuses" xsi:type="string">Complete,Closed</data> <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionPartialFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php index f2cd745e96d83..1a22ea947f85a 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php @@ -64,8 +64,7 @@ public function testProcessIpnRequestFullRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); $creditmemo = current($creditmemoItems); - //Totally refunded orders still can be shipped - $this->assertEquals(Order::STATE_PROCESSING, $order->getState()) ; + $this->assertEquals(Order::STATE_CLOSED, $order->getState()) ; $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(Creditmemo::STATE_REFUNDED, $creditmemo->getState()); $this->assertEquals(10, $order->getSubtotalRefunded()); @@ -147,8 +146,7 @@ public function testProcessIpnRequestRestRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); - //Totally refunded orders still can be shipped - $this->assertEquals(Order::STATE_PROCESSING, $order->getState()) ; + $this->assertEquals(Order::STATE_CLOSED, $order->getState()) ; $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(10, $order->getSubtotalRefunded()); $this->assertEquals(10, $order->getBaseSubtotalRefunded()); From 8bdcec2151953eb91ee61075917e60648662395f Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Tue, 13 Nov 2018 09:43:19 -0600 Subject: [PATCH 0671/1158] MAGETWO-96262: Order with simple product after partial cancellation and credit memo has status 'Processing' --- ...ssertOrderCancelMassActionPartialFailMessage.php | 13 ++----------- .../Sales/Test/TestCase/MassOrdersUpdateTest.xml | 4 ++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php index 6aed5cd39aaad..9208032a316ef 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php @@ -15,15 +15,10 @@ */ class AssertOrderCancelMassActionPartialFailMessage extends AbstractConstraint { - /** - * Message displayed after cancel order from archive - */ - const SUCCESS_MESSAGE = 'We canceled 1 order(s).'; - /** * Text value to be checked */ - const FAIL_CANCEL_MESSAGE = '1 order(s) cannot be canceled.'; + const FAIL_CANCEL_MESSAGE = 'You cannot cancel the order(s).'; /** * Assert cancel fail message is displayed on order index page @@ -37,10 +32,6 @@ public function processAssert(OrderIndex $orderIndex) self::FAIL_CANCEL_MESSAGE, $orderIndex->getMessagesBlock()->getErrorMessage() ); - \PHPUnit\Framework\Assert::assertEquals( - self::SUCCESS_MESSAGE, - $orderIndex->getMessagesBlock()->getSuccessMessage() - ); } /** @@ -50,6 +41,6 @@ public function processAssert(OrderIndex $orderIndex) */ public function toString() { - return 'Cancel and success fail message is displayed on order index page.'; + return 'Cancel fail message is displayed on order index page.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml index f59e6df845b6e..99e25b062846b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml @@ -18,7 +18,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation2"> - <data name="description" xsi:type="string">try to cancel orders in status Complete, Canceled</data> + <data name="description" xsi:type="string">try to cancel orders in status Complete, Closed</data> <data name="steps" xsi:type="string">invoice, shipment|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> @@ -31,7 +31,7 @@ <data name="steps" xsi:type="string">invoice|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Processing,Canceled</data> + <data name="resultStatuses" xsi:type="string">Processing,Closed</data> <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionPartialFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> From 9d0773b8db2c2a74e76702c08a87b90a8976b4be Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Tue, 13 Nov 2018 18:53:30 +0200 Subject: [PATCH 0672/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - improve CE locator that is different from B2B --- .../Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml index bae7069859937..afc60e80954e2 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml @@ -11,4 +11,9 @@ <!-- This actionGroup was created to be merged from B2B because B2B has a very different form control here --> <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="NOT LOGGED IN" stepKey="selectCustomerGroup"/> </actionGroup> + + <actionGroup name="selectRetailerCustomerGroup"> + <!-- This actionGroup was created to be merged from B2B. Retailer Customer Group --> + <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="Retailer" stepKey="selectCustomerGroup"/> + </actionGroup> </actionGroups> From 08ac92e88a9420e358818f29091723454d937f9c Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Tue, 13 Nov 2018 19:02:27 +0200 Subject: [PATCH 0673/1158] MAGETWO-96306: Customer address street data is displayed incorrectly on default billing/shipping blocks --- .../Customer/view/adminhtml/web/template/default-address.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html index 96de88a1145f4..1dd583b990202 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -17,7 +17,8 @@ </if> <if args="address.street"> <text args="address.street" if="_.isString(address.street)"/> - <text args="_.values(address.street).join(', ')" ifnot="_.isString(address.street)"/> + <text args="_.values(address.street).filter(value => _.isString(value)).join(', ')" + ifnot="_.isString(address.street)"/> <br/> </if> <text args="address.city + ', '" if="address.city"/> From 3b84172faf8612ca7fc54c4c3bb131923e521c01 Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Tue, 13 Nov 2018 19:07:45 +0200 Subject: [PATCH 0674/1158] Small refactoring --- app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php index f7467ef07aadb..7c8a92397d8c5 100644 --- a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php +++ b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php @@ -161,12 +161,11 @@ public function afterDelete(CustomerRepository $subject, $result, CustomerInterf public function afterGetById(CustomerRepository $subject, CustomerInterface $customer) { $extensionAttributes = $customer->getExtensionAttributes(); - + $storeId = $this->storeManager->getStore()->getId(); + $customer->setStoreId($storeId); if ($extensionAttributes === null) { /** @var CustomerExtensionInterface $extensionAttributes */ $extensionAttributes = $this->extensionFactory->create(CustomerInterface::class); - $storeId = $this->storeManager->getStore()->getId(); - $customer->setStoreId($storeId); $customer->setExtensionAttributes($extensionAttributes); } if ($extensionAttributes->getIsSubscribed() === null) { From 702072502f924e380149709ecfe5247ff4a7d510 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Tue, 13 Nov 2018 19:16:27 +0200 Subject: [PATCH 0675/1158] GraphQL-43: [Query] My Account > My Wish List - Refactoring --- .../Model/ProductDataProvider.php} | 21 ++++- .../Model/Resolver/ProductResolver.php | 53 ++++++++++++ .../WishlistItemsProductsResolver.php | 56 ------------- .../Model/Resolver/WishlistItemsResolver.php | 81 ++++++++++++++----- .../Model/Resolver/WishlistResolver.php | 53 +++++++----- .../Model/WishlistDataProvider.php | 37 --------- .../Model/WishlistItemsDataProvider.php | 50 ------------ .../WishlistGraphQl/etc/schema.graphqls | 16 ++-- .../Magento/GraphQl/Wishlist/WishlistTest.php | 60 +++++++++----- 9 files changed, 214 insertions(+), 213 deletions(-) rename app/code/Magento/{WishlistGraphQl/Model/WishlistItemsProductDataProvider.php => CatalogGraphQl/Model/ProductDataProvider.php} (60%) create mode 100644 app/code/Magento/WishlistGraphQl/Model/Resolver/ProductResolver.php delete mode 100644 app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php delete mode 100644 app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php delete mode 100644 app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php b/app/code/Magento/CatalogGraphQl/Model/ProductDataProvider.php similarity index 60% rename from app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php rename to app/code/Magento/CatalogGraphQl/Model/ProductDataProvider.php index 76df065a80702..0d38490407e7c 100644 --- a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsProductDataProvider.php +++ b/app/code/Magento/CatalogGraphQl/Model/ProductDataProvider.php @@ -5,23 +5,38 @@ */ declare(strict_types=1); -namespace Magento\WishlistGraphQl\Model; +namespace Magento\CatalogGraphQl\Model; use Magento\Catalog\Api\ProductRepositoryInterface; -class WishlistItemsProductDataProvider +/** + * Product data provider + * + * TODO: will be replaces on deferred mechanism + */ +class ProductDataProvider { /** * @var ProductRepositoryInterface */ private $productRepository; + /** + * @param ProductRepositoryInterface $productRepository + */ public function __construct(ProductRepositoryInterface $productRepository) { $this->productRepository = $productRepository; } - public function getProductDataById(int $productId) { + /** + * Get product data by id + * + * @param int $productId + * @return array + */ + public function getProductDataById(int $productId): array + { $product = $this->productRepository->getById($productId); $productData = $product->toArray(); $productData['model'] = $product; diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/ProductResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/ProductResolver.php new file mode 100644 index 0000000000000..b59582a189f60 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/ProductResolver.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\WishlistGraphQl\Model\Resolver; + +use Magento\CatalogGraphQl\Model\ProductDataProvider; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Wishlist\Model\Item; + +/** + * Fetches the Product data according to the GraphQL schema + */ +class ProductResolver implements ResolverInterface +{ + /** + * @var ProductDataProvider + */ + private $productDataProvider; + + /** + * @param ProductDataProvider $productDataProvider + */ + public function __construct(ProductDataProvider $productDataProvider) + { + $this->productDataProvider = $productDataProvider; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (!isset($value['model'])) { + throw new LocalizedException(__('Missing key "model" in Wishlist Item value data')); + } + /** @var Item $wishlistItem */ + $wishlistItem = $value['model']; + + return $this->productDataProvider->getProductDataById($wishlistItem->getProductId()); + } +} diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php deleted file mode 100644 index 26ace0e849e3f..0000000000000 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsProductsResolver.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\WishlistGraphQl\Model\Resolver; - -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; -use Magento\Framework\GraphQl\Query\Resolver\Value; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\WishlistGraphQl\Model\WishlistItemsProductDataProvider; - -class WishlistItemsProductsResolver implements ResolverInterface -{ - /** - * @var WishlistItemsProductDataProvider - */ - private $productDataProvider; - - public function __construct(WishlistItemsProductDataProvider $productDataProvider) - { - $this->productDataProvider = $productDataProvider; - } - - - /** - * Fetches the data from persistence models and format it according to the GraphQL schema. - * - * @param \Magento\Framework\GraphQl\Config\Element\Field $field - * @param ContextInterface $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * @throws \Exception - * @return mixed|Value - */ - public function resolve( - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!isset($value['product_id'])) { - throw new GraphQlInputException( - __('Missing key %1 in wishlist item data', ['product_id']) - ); - } - return $this->productDataProvider->getProductDataById($value['product_id']); - } -} diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php index 707618b10602d..033c63441e907 100644 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php @@ -7,36 +7,46 @@ namespace Magento\WishlistGraphQl\Model\Resolver; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; -use Magento\Framework\GraphQl\Query\Resolver\Value; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Wishlist\Model\ResourceModel\Item\Collection as WishlistItemCollection; +use Magento\Wishlist\Model\ResourceModel\Item\CollectionFactory as WishlistItemCollectionFactory; use Magento\Wishlist\Model\Item; -use Magento\WishlistGraphQl\Model\WishlistItemsDataProvider; +use Magento\Wishlist\Model\Wishlist; +/** + * Fetches the Wishlist Items data according to the GraphQL schema + */ class WishlistItemsResolver implements ResolverInterface { /** - * @var WishlistItemsDataProvider + * @var WishlistItemCollectionFactory */ - private $wishlistItemsDataProvider; + private $wishlistItemCollectionFactory; - public function __construct(WishlistItemsDataProvider $wishlistItemsDataProvider) - { - $this->wishlistItemsDataProvider = $wishlistItemsDataProvider; + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @param WishlistItemCollectionFactory $wishlistItemCollectionFactory + * @param StoreManagerInterface $storeManager + */ + public function __construct( + WishlistItemCollectionFactory $wishlistItemCollectionFactory, + StoreManagerInterface $storeManager + ) { + $this->wishlistItemCollectionFactory = $wishlistItemCollectionFactory; + $this->storeManager = $storeManager; } /** - * Fetches the data from persistence models and format it according to the GraphQL schema. - * - * @param \Magento\Framework\GraphQl\Config\Element\Field $field - * @param ContextInterface $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * @throws \Exception - * @return mixed|Value + * @inheritdoc */ public function resolve( Field $field, @@ -45,14 +55,41 @@ public function resolve( array $value = null, array $args = null ) { - return array_map(function (Item $wishlistItem) { - return [ + if (!isset($value['model'])) { + throw new LocalizedException(__('Missing key "model" in Wishlist value data')); + } + /** @var Wishlist $wishlist */ + $wishlist = $value['model']; + + $wishlistItems = $this->getWishListItems($wishlist); + + $data = []; + foreach ($wishlistItems as $wishlistItem) { + $data[] = [ 'id' => $wishlistItem->getId(), 'qty' => $wishlistItem->getData('qty'), - 'description' => (string)$wishlistItem->getDescription(), + 'description' => $wishlistItem->getDescription(), 'added_at' => $wishlistItem->getAddedAt(), - 'product_id' => (int)$wishlistItem->getProductId() + 'model' => $wishlistItem, ]; - }, $this->wishlistItemsDataProvider->getWishlistItemsForCustomer($context->getUserId())); + } + return $data; + } + + /** + * @param Wishlist $wishlist + * @return Item[] + */ + private function getWishListItems(Wishlist $wishlist): array + { + /** @var WishlistItemCollection $wishlistItemCollection */ + $wishlistItemCollection = $this->wishlistItemCollectionFactory->create(); + $wishlistItemCollection + ->addWishlistFilter($wishlist) + ->addStoreFilter(array_map(function (StoreInterface $store) { + return $store->getId(); + }, $this->storeManager->getStores())) + ->setVisibilityFilter(); + return $wishlistItemCollection->getItems(); } } diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php index ba1a6e935c10e..e3a788af2ea7e 100644 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistResolver.php @@ -8,34 +8,39 @@ namespace Magento\WishlistGraphQl\Model\Resolver; use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; -use Magento\Framework\GraphQl\Query\Resolver\Value; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\WishlistGraphQl\Model\WishlistDataProvider; +use Magento\Wishlist\Model\ResourceModel\Wishlist as WishlistResourceModel; +use Magento\Wishlist\Model\Wishlist; +use Magento\Wishlist\Model\WishlistFactory; +/** + * Fetches the Wishlist data according to the GraphQL schema + */ class WishlistResolver implements ResolverInterface { /** - * @var WishlistDataProvider + * @var WishlistResourceModel + */ + private $wishlistResource; + + /** + * @var WishlistFactory */ - private $wishlistDataProvider; + private $wishlistFactory; - public function __construct(WishlistDataProvider $wishlistDataProvider) + /** + * @param WishlistResourceModel $wishlistResource + * @param WishlistFactory $wishlistFactory + */ + public function __construct(WishlistResourceModel $wishlistResource, WishlistFactory $wishlistFactory) { - $this->wishlistDataProvider = $wishlistDataProvider; + $this->wishlistResource = $wishlistResource; + $this->wishlistFactory = $wishlistFactory; } /** - * Fetches the data from persistence models and format it according to the GraphQL schema. - * - * @param \Magento\Framework\GraphQl\Config\Element\Field $field - * @param ContextInterface $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * @throws \Exception - * @return mixed|Value + * @inheritdoc */ public function resolve( Field $field, @@ -44,10 +49,22 @@ public function resolve( array $value = null, array $args = null ) { - $wishlist = $this->wishlistDataProvider->getWishlistForCustomer($context->getUserId()); + $customerId = $context->getUserId(); + + /** @var Wishlist $wishlist */ + $wishlist = $this->wishlistFactory->create(); + $this->wishlistResource->load($wishlist, $customerId, 'customer_id'); + + if (null === $wishlist->getId()) { + return []; + } + return [ 'sharing_code' => $wishlist->getSharingCode(), - 'updated_at' => $wishlist->getUpdatedAt() + 'updated_at' => $wishlist->getUpdatedAt(), + 'items_count' => $wishlist->getItemsCount(), + 'name' => $wishlist->getName(), + 'model' => $wishlist, ]; } } diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php deleted file mode 100644 index a62ddebd91120..0000000000000 --- a/app/code/Magento/WishlistGraphQl/Model/WishlistDataProvider.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\WishlistGraphQl\Model; - -use Magento\Wishlist\Model\ResourceModel\Wishlist; -use Magento\Wishlist\Model\WishlistFactory; - -class WishlistDataProvider -{ - /** - * @var Wishlist - */ - private $wishlistResource; - /** - * @var WishlistFactory - */ - private $wishlistFactory; - - public function __construct(Wishlist $wishlistResource, WishlistFactory $wishlistFactory) - { - $this->wishlistResource = $wishlistResource; - $this->wishlistFactory = $wishlistFactory; - } - - public function getWishlistForCustomer(int $customerId): \Magento\Wishlist\Model\Wishlist - { - /** @var \Magento\Wishlist\Model\Wishlist $wishlist */ - $wishlist = $this->wishlistFactory->create(); - $this->wishlistResource->load($wishlist, $customerId, 'customer_id'); - return $wishlist; - } -} diff --git a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php b/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php deleted file mode 100644 index ca87b23460fc7..0000000000000 --- a/app/code/Magento/WishlistGraphQl/Model/WishlistItemsDataProvider.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\WishlistGraphQl\Model; - -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\StoreManagerInterface; -use Magento\Wishlist\Model\Item; -use Magento\Wishlist\Model\ResourceModel\Item\CollectionFactory as WishlistItemCollectionFactory; - -class WishlistItemsDataProvider -{ - - /** - * @var WishlistItemCollectionFactory - */ - private $wishlistItemCollectionFactory; - /** - * @var StoreManagerInterface - */ - private $storeManager; - - public function __construct( - WishlistItemCollectionFactory $wishlistItemCollectionFactory, - StoreManagerInterface $storeManager - ) { - $this->wishlistItemCollectionFactory = $wishlistItemCollectionFactory; - $this->storeManager = $storeManager; - } - - /** - * @param int $customerId - * @return Item[] - */ - public function getWishlistItemsForCustomer(int $customerId): array - { - $wishlistItemCollection = $this->wishlistItemCollectionFactory->create(); - $wishlistItemCollection->addCustomerIdFilter($customerId); - $wishlistItemCollection->addStoreFilter(array_map(function (StoreInterface $store) { - return $store->getId(); - }, $this->storeManager->getStores())); - $wishlistItemCollection->setVisibilityFilter(); - $wishlistItemCollection->load(); - return $wishlistItemCollection->getItems(); - } -} diff --git a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls index 5c6d701138560..a63ec6eff6f5b 100644 --- a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls @@ -7,14 +7,16 @@ type Query { type WishlistOutput { items: [WishlistItem] @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsResolver") @doc(description: "todo"), - sharing_code: String! @doc(description: "todo"), - updated_at: String! @doc(description: "todo") + items_count: Int @doc(description: "todo"), + name: String @doc(description: "todo"), + sharing_code: String @doc(description: "todo"), + updated_at: String @doc(description: "todo") } type WishlistItem { - id: Int! @doc(description: "todo") - qty: Float! @doc(description: "todo"), - description: String! @doc(description: "todo"), - added_at: String! @doc(description: "todo"), - product: ProductInterface @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsProductsResolver") + id: Int @doc(description: "todo") + qty: Float @doc(description: "todo"), + description: String @doc(description: "todo"), + added_at: String @doc(description: "todo"), + product: ProductInterface @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\ProductResolver") } \ No newline at end of file diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php index 53577d02df50f..d570fc09b7714 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/WishlistTest.php @@ -8,40 +8,45 @@ namespace Magento\GraphQl\Wishlist; use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; use Magento\Wishlist\Model\Item; +use Magento\Wishlist\Model\ResourceModel\Wishlist as WishlistResourceModel; +use Magento\Wishlist\Model\WishlistFactory; class WishlistTest extends GraphQlAbstract { - /** - * @var \Magento\TestFramework\ObjectManager - */ - private $objectManager; /** * @var CustomerTokenServiceInterface */ private $customerTokenService; + /** + * @var WishlistFactory + */ + private $wishlistFactory; + + /** + * @var WishlistResourceModel + */ + private $wishlistResource; + protected function setUp() { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->customerTokenService = $this->objectManager->get(CustomerTokenServiceInterface::class); + $this->customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class); + $this->wishlistFactory = Bootstrap::getObjectManager()->get(WishlistFactory::class); + $this->wishlistResource = Bootstrap::getObjectManager()->get(WishlistResourceModel::class); } /** - * Verify the fields of CMS Block selected by identifiers - * * @magentoApiDataFixture Magento/Wishlist/_files/wishlist.php - * @throws \Magento\Framework\Exception\AuthenticationException - * @throws \Exception */ - public function testGetCustomersWishlist(): void + public function testGetCustomerWishlist(): void { /** @var \Magento\Wishlist\Model\Wishlist $wishlist */ - $wishlist = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Wishlist\Model\Wishlist::class - ); - $wishlist->loadByCustomerId(1, true); + $wishlist = $this->wishlistFactory->create(); + $this->wishlistResource->load($wishlist, 1, 'customer_id'); + /** @var Item $wishlistItem */ $wishlistItem = $wishlist->getItemCollection()->getFirstItem(); $wishlistItemProduct = $wishlistItem->getProduct(); @@ -49,26 +54,41 @@ public function testGetCustomersWishlist(): void <<<QUERY { wishlist { + items_count + name + sharing_code + updated_at items { id qty + description + added_at product { sku name } - description - added_at } - sharing_code - updated_at } } QUERY; - $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders('customer@example.com', 'password')); + $response = $this->graphQlQuery( + $query, + [], + '', + $this->getCustomerAuthHeaders('customer@example.com', 'password') + ); + + $this->assertEquals($wishlist->getItemsCount(), $response['wishlist']['items_count']); + $this->assertEquals($wishlist->getName(), $response['wishlist']['name']); $this->assertEquals($wishlist->getSharingCode(), $response['wishlist']['sharing_code']); + $this->assertEquals($wishlist->getUpdatedAt(), $response['wishlist']['updated_at']); + + $this->assertEquals($wishlistItem->getId(), $response['wishlist']['items'][0]['id']); $this->assertEquals($wishlistItem->getData('qty'), $response['wishlist']['items'][0]['qty']); $this->assertEquals($wishlistItem->getDescription(), $response['wishlist']['items'][0]['description']); + $this->assertEquals($wishlistItem->getAddedAt(), $response['wishlist']['items'][0]['added_at']); + $this->assertEquals($wishlistItemProduct->getSku(), $response['wishlist']['items'][0]['product']['sku']); $this->assertEquals($wishlistItemProduct->getName(), $response['wishlist']['items'][0]['product']['name']); } From 0d3d631aba4c2c536fcf654b726cf085212de5dd Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Tue, 13 Nov 2018 09:29:11 -0800 Subject: [PATCH 0676/1158] MAGETWO-96318: Revert MAGETWO-64316 due to performance degradation --- .../Model/WebapiProductUrlPathGenerator.php | 72 ------------------- .../CatalogUrlRewrite/etc/webapi_rest/di.xml | 10 --- .../CatalogUrlRewrite/etc/webapi_soap/di.xml | 10 --- .../Api/ProductRepositoryInterfaceTest.php | 56 --------------- 4 files changed, 148 deletions(-) delete mode 100644 app/code/Magento/CatalogUrlRewrite/Model/WebapiProductUrlPathGenerator.php delete mode 100644 app/code/Magento/CatalogUrlRewrite/etc/webapi_rest/di.xml delete mode 100644 app/code/Magento/CatalogUrlRewrite/etc/webapi_soap/di.xml diff --git a/app/code/Magento/CatalogUrlRewrite/Model/WebapiProductUrlPathGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/WebapiProductUrlPathGenerator.php deleted file mode 100644 index ae93b76b31579..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/Model/WebapiProductUrlPathGenerator.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -declare(strict_types=1); - -namespace Magento\CatalogUrlRewrite\Model; - -use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection; -use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; - -/** - * Class for creating product url through web-api. - */ -class WebapiProductUrlPathGenerator extends ProductUrlPathGenerator -{ - /** - * @var CollectionFactory - */ - private $collectionFactory; - - /** - * @param \Magento\Store\Model\StoreManagerInterface $storeManager - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - * @param \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator $categoryUrlPathGenerator - * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository - * @param CollectionFactory $collectionFactory - */ - public function __construct( - \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator $categoryUrlPathGenerator, - \Magento\Catalog\Api\ProductRepositoryInterface $productRepository, - CollectionFactory $collectionFactory - ) { - parent::__construct($storeManager, $scopeConfig, $categoryUrlPathGenerator, $productRepository); - $this->collectionFactory = $collectionFactory; - } - - /** - * @inheritdoc - */ - protected function prepareProductUrlKey(\Magento\Catalog\Model\Product $product) - { - $urlKey = $product->getUrlKey(); - if ($urlKey === '' || $urlKey === null) { - $urlKey = $this->prepareUrlKey($product->formatUrlKey($product->getName())); - } - return $product->formatUrlKey($urlKey); - } - - /** - * Crete url key if it does not exist yet. - * - * @param string $urlKey - * @return string - */ - private function prepareUrlKey(string $urlKey) : string - { - /** @var ProductCollection $collection */ - $collection = $this->collectionFactory->create(); - $collection->addFieldToFilter('url_key', ['like' => $urlKey]); - if ($collection->getSize() !== 0) { - $urlKey = $urlKey . '-1'; - $urlKey = $this->prepareUrlKey($urlKey); - } - - return $urlKey; - } -} diff --git a/app/code/Magento/CatalogUrlRewrite/etc/webapi_rest/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/webapi_rest/di.xml deleted file mode 100644 index ac8beb362f0fb..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/etc/webapi_rest/di.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <preference for="Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator" type="Magento\CatalogUrlRewrite\Model\WebapiProductUrlPathGenerator"/> -</config> diff --git a/app/code/Magento/CatalogUrlRewrite/etc/webapi_soap/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/webapi_soap/di.xml deleted file mode 100644 index ac8beb362f0fb..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/etc/webapi_soap/di.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <preference for="Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator" type="Magento\CatalogUrlRewrite\Model\WebapiProductUrlPathGenerator"/> -</config> diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php index 1017fb6716709..3e935e1d7ae9b 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php @@ -159,62 +159,6 @@ private function loadWebsiteByCode($websiteCode) return $website; } - /** - * Test for check that 2 same product create and url_key save. - * - * @return void - */ - public function testSaveTwoSameProduct() - { - $serviceInfo = [ - 'rest' => [ - 'resourcePath' => self::RESOURCE_PATH, - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, - ], - 'soap' => [ - 'service' => self::SERVICE_NAME, - 'serviceVersion' => self::SERVICE_VERSION, - 'operation' => self::SERVICE_NAME . 'Save', - ], - ]; - - $product1 = [ - 'product' => [ - 'attribute_set_id' => 4, - 'name' => "Test API 1", - 'price' => 254.13, - 'sku' => '1234' - ] - ]; - $product2 = [ - 'product' => [ - 'attribute_set_id' => 4, - 'name' => "Test API 1", - 'price' => 254.13, - 'sku' => '1235' - ] - ]; - - $product1 = $this->_webApiCall($serviceInfo, $product1); - $response = $this->_webApiCall($serviceInfo, $product2); - - $index = null; - foreach ($response['custom_attributes'] as $key => $customAttribute) { - if ($customAttribute['attribute_code'] == 'url_key') { - $index = $key; - break; - } - } - - $this->assertArrayHasKey(ProductInterface::SKU, $response); - - $expectedResult = $product1['custom_attributes'][$index]['value'] . '-1'; - $this->assertEquals($expectedResult, $response['custom_attributes'][$index]['value']); - - $this->deleteProduct('1234'); - $this->deleteProduct('1235'); - } - /** * Test removing association between product and website 1 * @magentoApiDataFixture Magento/Catalog/_files/product_with_two_websites.php From ce1a7cec2053f19753c5b003fae74d538428a7ee Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Tue, 13 Nov 2018 19:31:29 +0200 Subject: [PATCH 0677/1158] MAGETWO-96209: Customer address grid actions send GET instead of POST request --- .../Magento/Customer/Controller/Adminhtml/Address/Delete.php | 4 ++-- .../Customer/Ui/Component/Listing/Address/Column/Actions.php | 1 + .../Customer/view/adminhtml/web/js/grid/columns/actions.js | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 65da3bca49e9b..711cd2473cdc5 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,7 +8,7 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; @@ -17,7 +17,7 @@ /** * Button for deletion of customer address in admin */ -class Delete extends Action implements HttpGetActionInterface +class Delete extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index 490a14169e7b7..7da6d3a6a86c5 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -113,6 +113,7 @@ public function prepareDataSource(array $dataSource): array ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Delete'), + 'post' => true, 'isAjax' => true, 'confirm' => [ 'title' => __('Delete address'), diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js index 43ab06c8014ee..4a62ce2e6eccf 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js @@ -18,8 +18,9 @@ define([ return Actions.extend({ defaults: { ajaxSettings: { - method: 'GET', - dataType: 'json' + method: 'POST', + dataType: 'json', + formKey: $('input[name="form_key"]').val() }, listens: { action: 'onAction' From 7c9de8e88705824b07378de2bca5ae383c5c80fb Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Tue, 13 Nov 2018 13:25:39 -0600 Subject: [PATCH 0678/1158] #13157 - Last Ordered Items block - bad js code --- .../frontend/templates/reorder/sidebar.phtml | 2 +- .../web/js/view/last-ordered-items.js | 27 ++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml b/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml index 370e034ead64a..9b3633fde60b4 100644 --- a/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml +++ b/app/code/Magento/Sales/view/frontend/templates/reorder/sidebar.phtml @@ -51,7 +51,7 @@ <div id="cart-sidebar-reorder-advice-container"></div> <div class="actions-toolbar"> <div class="primary" - data-bind="visible: lastOrderedItems.isShowAddToCart"> + data-bind="visible: isShowAddToCart"> <button type="submit" title="<?= /* @escapeNotVerified */ __('Add to Cart') ?>" class="action tocart primary"> <span><?= /* @escapeNotVerified */ __('Add to Cart') ?></span> </button> diff --git a/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js b/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js index 74465128f8c72..17e61a77d98a3 100644 --- a/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js +++ b/app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js @@ -11,18 +11,37 @@ define([ 'use strict'; return Component.extend({ + defaults: { + isShowAddToCart: false + }, + /** @inheritdoc */ initialize: function () { - var isShowAddToCart; - this._super(); this.lastOrderedItems = customerData.get('last-ordered-items'); + this.lastOrderedItems.subscribe(this.checkSalableItems.bind(this)); + this.checkSalableItems(); + + return this; + }, + + /** @inheritdoc */ + initObservable: function () { + this._super() + .observe('isShowAddToCart'); + + return this; + }, - isShowAddToCart = _.some(this.lastOrderedItems().items, { + /** + * Check if items is_saleable and change add to cart button visibility. + */ + checkSalableItems: function () { + var isShowAddToCart = _.some(this.lastOrderedItems().items, { 'is_saleable': true }); - this.lastOrderedItems.isShowAddToCart = isShowAddToCart; + this.isShowAddToCart(isShowAddToCart); } }); }); From 39fe0fa91f1eb7146af7f7d542f54dfc0f764b20 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Tue, 13 Nov 2018 13:28:48 -0600 Subject: [PATCH 0679/1158] MQE-1339: Bump MFTF version in Magento - MFTF version bump and lockfile update --- composer.json | 2 +- composer.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 44452b6b4745f..00e5767fb4d6a 100644 --- a/composer.json +++ b/composer.json @@ -84,7 +84,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "~2.13.0", "lusitanian/oauth": "~0.8.10", - "magento/magento2-functional-testing-framework": "2.3.10", + "magento/magento2-functional-testing-framework": "2.3.11", "pdepend/pdepend": "2.5.2", "phpmd/phpmd": "@stable", "phpunit/phpunit": "~6.5.0", diff --git a/composer.lock b/composer.lock index 3565ab2420e05..7ce9efeb65e6f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "94ba8bea0470c1e4599c17145dcf3508", + "content-hash": "243bbfba7578f2084615fa0c092f87a8", "packages": [ { "name": "braintree/braintree_php", @@ -6351,16 +6351,16 @@ }, { "name": "magento/magento2-functional-testing-framework", - "version": "2.3.10", + "version": "2.3.11", "source": { "type": "git", "url": "https://github.com/magento/magento2-functional-testing-framework.git", - "reference": "7cd80dbf1af405473f1a976c3b75097a0f27725d" + "reference": "3ca1bd74228a61bd05520bed1ef88b5a19764d92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/7cd80dbf1af405473f1a976c3b75097a0f27725d", - "reference": "7cd80dbf1af405473f1a976c3b75097a0f27725d", + "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/3ca1bd74228a61bd05520bed1ef88b5a19764d92", + "reference": "3ca1bd74228a61bd05520bed1ef88b5a19764d92", "shasum": "" }, "require": { @@ -6418,7 +6418,7 @@ "magento", "testing" ], - "time": "2018-11-06T20:54:16+00:00" + "time": "2018-11-13T18:22:25+00:00" }, { "name": "moontoast/math", From f6a6d11bc0219bc4847745d264f8991d04d5372e Mon Sep 17 00:00:00 2001 From: Graham Wharton <graham@gwharton.me.uk> Date: Tue, 13 Nov 2018 20:00:59 +0000 Subject: [PATCH 0680/1158] Made logo clickable on home page --- .../frontend/templates/html/header/logo.phtml | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml index 17f8d7c70f574..79b891b7e55e6 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml @@ -12,19 +12,11 @@ ?> <?php $storeName = $block->getThemeName() ? $block->getThemeName() : $block->getLogoAlt();?> <span data-action="toggle-nav" class="action nav-toggle"><span><?= /* @escapeNotVerified */ __('Toggle Nav') ?></span></span> -<?php if ($block->isHomePage()):?> - <strong class="logo"> -<?php else: ?> - <a class="logo" href="<?= $block->getUrl('') ?>" title="<?= /* @escapeNotVerified */ $storeName ?>"> -<?php endif ?> - <img src="<?= /* @escapeNotVerified */ $block->getLogoSrc() ?>" - title="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" - alt="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" - <?= $block->getLogoWidth() ? 'width="' . $block->getLogoWidth() . '"' : '' ?> - <?= $block->getLogoHeight() ? 'height="' . $block->getLogoHeight() . '"' : '' ?> - /> -<?php if ($block->isHomePage()):?> - </strong> -<?php else:?> - </a> -<?php endif?> +<a class="logo" href="<?= $block->getUrl('') ?>" title="<?= /* @escapeNotVerified */ $storeName ?>"> + <img src="<?= /* @escapeNotVerified */ $block->getLogoSrc() ?>" + title="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" + alt="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" + <?= $block->getLogoWidth() ? 'width="' . $block->getLogoWidth() . '"' : '' ?> + <?= $block->getLogoHeight() ? 'height="' . $block->getLogoHeight() . '"' : '' ?> + /> +</a> From 0dfe7ffb2201ff360e9c34c123ae73b9a06af83f Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Tue, 13 Nov 2018 18:22:12 -0600 Subject: [PATCH 0681/1158] MAGETWO-96262: Order with simple product after partial cancellation and credit memo has status 'Processing' --- .../Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml index 9a7b3f1ff6bbf..a7bf82588f7c7 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml @@ -12,6 +12,7 @@ <element name="itemName" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-product .product-title" parameterized="true"/> <element name="itemSku" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-product .product-sku-block" parameterized="true"/> <element name="itemQty" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-ordered-qty .qty-table" parameterized="true"/> + <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-qty input.qty-item" parameterized="true"/> <element name="nameColumn" type="text" selector=".order-shipment-table .col-product .product-title"/> <element name="skuColumn" type="text" selector=".order-shipment-table .col-product .product-sku-block"/> </section> From d3078dbd147a6fb30592370256f34c84f078fa33 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Wed, 14 Nov 2018 10:17:15 +0300 Subject: [PATCH 0682/1158] MAGETWO-71022: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value - Stabilize test --- .../Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml index 4ab1e3327960c..00f290cd94e70 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml @@ -13,5 +13,6 @@ <element name="email" type="input" selector="#email"/> <element name="requiredGroup" type="text" selector=".admin__field.required[data-ui-id='billing-address-fieldset-element-form-field-group-id']"/> <element name="requiredEmail" type="text" selector=".admin__field.required[data-ui-id='billing-address-fieldset-element-form-field-email']"/> + <element name="defaultGeneral" type="text" selector="//*[text()='Default (General)']" time="15"/> </section> </sections> \ No newline at end of file From 0acab420008a958fcbbb635cd0317681a5f06309 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina <Veronika_Kurochkina@epam.com> Date: Wed, 14 Nov 2018 11:14:58 +0300 Subject: [PATCH 0683/1158] MAGETWO-62728: My Wishlist - quantity input box issue - Fix static tests --- .../Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js index 8a20d2925849a..cab130f7c2104 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js @@ -188,7 +188,7 @@ define([ /** * Bind form submit. * - * @param {boolean} isFileUploaded + * @param {Boolean} isFileUploaded */ bindFormSubmit: function (isFileUploaded) { var self = this; @@ -199,6 +199,7 @@ define([ if (!$($(self.options.qtyInfo).closest('form')).valid()) { event.stopPropagation(); event.preventDefault(); + return; } From a9bdbdb95a4156aa3e05d31d245b3057c08f7080 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Wed, 14 Nov 2018 11:21:43 +0200 Subject: [PATCH 0684/1158] magento/magento2#13095: [Forwardport] No locale for Swedish (Finland). --- lib/internal/Magento/Framework/Locale/Config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/Locale/Config.php b/lib/internal/Magento/Framework/Locale/Config.php index 8767bd515db82..790fa9c924c8e 100644 --- a/lib/internal/Magento/Framework/Locale/Config.php +++ b/lib/internal/Magento/Framework/Locale/Config.php @@ -90,6 +90,7 @@ class Config implements \Magento\Framework\Locale\ConfigInterface 'sq_AL', /*Albanian (Albania)*/ 'sr_Cyrl_RS', /*Serbian (Serbia)*/ 'sv_SE', /*Swedish (Sweden)*/ + 'sv_FI', /*Swedish (Finland)*/ 'sw_KE', /*Swahili (Kenya)*/ 'th_TH', /*Thai (Thailand)*/ 'tr_TR', /*Turkish (Turkey)*/ From ace100593b2903cbd79b9f3b4d0f49108b5465d4 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Wed, 31 Oct 2018 10:17:55 +0200 Subject: [PATCH 0685/1158] ENGCOM-3449: Fix/add expresion. --- .../Db/Collection/AbstractTest.php | 38 +++++++++++++++++++ .../Db/Collection/AbstractCollection.php | 14 +++++-- .../Db/Collection/AbstractCollectionTest.php | 3 +- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractTest.php b/dev/tests/integration/testsuite/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractTest.php index 419a7d04b778a..2ee0953dcdbf1 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractTest.php @@ -72,4 +72,42 @@ public function testGetAllIdsWithBind() $this->_model->addBindParam('code', 'admin'); $this->assertEquals(['0'], $this->_model->getAllIds()); } + + /** + * Check add field to select doesn't remove expression field from select. + * + * @return void + */ + public function testAddExpressionFieldToSelectWithAdditionalFields() + { + $expectedColumns = ['code', 'test_field']; + $actualColumns = []; + + $testExpression = new \Zend_Db_Expr('(sort_order + group_id)'); + $this->_model->addExpressionFieldToSelect('test_field', $testExpression, ['sort_order', 'group_id']); + $this->_model->addFieldToSelect('code', 'code'); + $columns = $this->_model->getSelect()->getPart(\Magento\Framework\DB\Select::COLUMNS); + foreach ($columns as $columnEntry) { + $actualColumns[] = $columnEntry[2]; + } + + $this->assertEquals($expectedColumns, $actualColumns); + } + + /** + * Check add expression field doesn't remove all fields from select. + * + * @return void + */ + public function testAddExpressionFieldToSelectWithoutAdditionalFields() + { + $expectedColumns = ['*', 'test_field']; + + $testExpression = new \Zend_Db_Expr('(sort_order + group_id)'); + $this->_model->addExpressionFieldToSelect('test_field', $testExpression, ['sort_order', 'group_id']); + $columns = $this->_model->getSelect()->getPart(\Magento\Framework\DB\Select::COLUMNS); + $actualColumns = [$columns[0][1], $columns[1][2]]; + + $this->assertEquals($expectedColumns, $actualColumns); + } } diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php index a88e013f5d2fe..6e1ea24a61a4a 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php @@ -45,6 +45,13 @@ abstract class AbstractCollection extends AbstractDb implements SourceProviderIn */ protected $_fieldsToSelect = null; + /** + * Expression fields to select in query. + * + * @var array + */ + private $expressionFieldsToSelect = []; + /** * Fields initial fields to select like id_field * @@ -205,7 +212,7 @@ protected function _initSelectFields() $columnsToSelect = []; foreach ($columns as $columnEntry) { list($correlationName, $column, $alias) = $columnEntry; - if ($correlationName !== 'main_table') { + if ($correlationName !== 'main_table' || isset($this->expressionFieldsToSelect[$alias])) { // Add joined fields to select if ($column instanceof \Zend_Db_Expr) { $column = $column->__toString(); @@ -346,9 +353,8 @@ public function addExpressionFieldToSelect($alias, $expression, $fields) $fullExpression = str_replace('{{' . $fieldKey . '}}', $fieldItem, $fullExpression); } - $fullExpression = new \Zend_Db_Expr($fullExpression); - $this->_fieldsToSelect[$alias] = $fullExpression; - $this->_fieldsToSelectChanged = true; + $this->getSelect()->columns([$alias => $fullExpression]); + $this->expressionFieldsToSelect[$alias] = $fullExpression; return $this; } diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php index 0eae94dabbbe8..4f27f083509d7 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php @@ -269,9 +269,8 @@ public function addFieldToSelectDataProvider() */ public function testAddExpressionFieldToSelect($alias, $expression, $fields, $expected) { + $this->selectMock->expects($this->once())->method('columns')->with($expected); $this->assertTrue($this->uut->addExpressionFieldToSelect($alias, $expression, $fields) instanceof Uut); - $this->assertEquals($expected, $this->uut->getFieldsToSelect()); - $this->assertTrue($this->uut->wereFieldsToSelectChanged()); } /** From cefc00668a9ccf72308c17e5a38aa8349e0d9058 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Wed, 14 Nov 2018 11:55:58 +0200 Subject: [PATCH 0686/1158] MAGETWO-96209: Customer address grid actions send GET instead of POST request - Pass form key parameter for post action in ajax request; - Add comments; --- .../Address/AbstractDefaultAddress.php | 4 ++-- .../Listing/Address/Column/Actions.php | 1 - .../adminhtml/web/js/grid/columns/actions.js | 18 +++++++++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index 9ec38f4929a87..64062139ef0fb 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -9,7 +9,7 @@ use Magento\Backend\App\Action; use Magento\Customer\Api\AddressRepositoryInterface; -use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Framework\Phrase; @@ -18,7 +18,7 @@ /** * Abstract class for customer default addresses changing */ -abstract class AbstractDefaultAddress extends Action implements HttpGetActionInterface +abstract class AbstractDefaultAddress extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index 7da6d3a6a86c5..490a14169e7b7 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -113,7 +113,6 @@ public function prepareDataSource(array $dataSource): array ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Delete'), - 'post' => true, 'isAjax' => true, 'confirm' => [ 'title' => __('Delete address'), diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js index 4a62ce2e6eccf..405e3e4b0dc69 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js @@ -19,14 +19,18 @@ define([ defaults: { ajaxSettings: { method: 'POST', - dataType: 'json', - formKey: $('input[name="form_key"]').val() + dataType: 'json' }, listens: { action: 'onAction' } }, + /** + * Reload customer address listing data source after customer address delete action + * + * @param {Object} data + */ onAction: function (data) { if (data.action === 'delete') { this.source().reload({ @@ -66,9 +70,17 @@ define([ } }, + /** + * Send customer address listing ajax request + * + * @param {String} href + */ request: function (href) { var settings = _.extend({}, this.ajaxSettings, { - url: href + url: href, + data: { + 'form_key': window.FORM_KEY + } }); $('body').trigger('processStart'); From 88a8763ab8646d2e7d69c344507a4701e0bcd3f0 Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Wed, 14 Nov 2018 12:03:34 +0200 Subject: [PATCH 0687/1158] Fix selection of all items which are not visible in ui grid --- app/code/Magento/Ui/view/base/web/js/grid/massactions.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/massactions.js b/app/code/Magento/Ui/view/base/web/js/grid/massactions.js index 48c04458ff49a..2e87e00fecda9 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/massactions.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/massactions.js @@ -153,6 +153,11 @@ define([ var itemsType = data.excludeMode ? 'excluded' : 'selected', selections = {}; + if (itemsType === 'excluded' && data['selected'].length){ + data['selected'] = _.difference(data['selected'], data['excluded']); + itemsType = 'selected'; + } + selections[itemsType] = data[itemsType]; if (!selections[itemsType].length) { From 303698fbcaf7c6fcd519e1d92014cf567a2f310b Mon Sep 17 00:00:00 2001 From: Khodu Vaishnav <khodu.vaishnav@krishtechnolabs.com> Date: Wed, 14 Nov 2018 15:56:48 +0530 Subject: [PATCH 0688/1158] 9130 remove the negative qty block. --- .../CatalogInventory/Block/Stockqty/AbstractStockqty.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php b/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php index 568fa600ec52d..7b27125f73fa6 100644 --- a/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php +++ b/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php @@ -131,7 +131,7 @@ public function getPlaceholderId() */ public function isMsgVisible() { - return $this->getStockQty() > 0 && $this->getStockQtyLeft() <= $this->getThresholdQty(); + return $this->getStockQty() > 0 && $this->getStockQtyLeft() > 0 && $this->getStockQtyLeft() <= $this->getThresholdQty(); } /** From 32e0f571322e7a37d38e6b3d19856bc4ce90143b Mon Sep 17 00:00:00 2001 From: Mariana Lashch <mlashch@magento.com> Date: Wed, 14 Nov 2018 13:15:58 +0200 Subject: [PATCH 0689/1158] MAGETWO-94472: [2.3] Unable to create credit memo for order placed via online payment with taxes and discounts - add changes to actiongroup --- .../Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml index afc60e80954e2..a794c67e736fc 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCartPriceRuleActionGroup.xml @@ -14,6 +14,6 @@ <actionGroup name="selectRetailerCustomerGroup"> <!-- This actionGroup was created to be merged from B2B. Retailer Customer Group --> - <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="Retailer" stepKey="selectCustomerGroup"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="Retailer" stepKey="selectRetailerCustomerGroup"/> </actionGroup> </actionGroups> From 66fb58bc8acbf04083bf6d332b5d83a9906e42a6 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 14 Nov 2018 16:02:45 +0200 Subject: [PATCH 0690/1158] GraphQl-41: [Query] My Account > My Orders -- Update composer files --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 7ce9efeb65e6f..2e1b77fe0a3c9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "243bbfba7578f2084615fa0c092f87a8", + "content-hash": "4f2fd2e8ffcc003e0a4a4116ec84b780", "packages": [ { "name": "braintree/braintree_php", From ce025fba563445590da3ca6f4d4d6caa5692ff34 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 14 Nov 2018 16:22:55 +0200 Subject: [PATCH 0691/1158] GraphQL-43: [Query] My Account > My Wish List - Update composer files --- app/code/Magento/WishlistGraphQl/composer.json | 1 + composer.lock | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/WishlistGraphQl/composer.json b/app/code/Magento/WishlistGraphQl/composer.json index 9226ea1754e6a..e0f342174f879 100644 --- a/app/code/Magento/WishlistGraphQl/composer.json +++ b/app/code/Magento/WishlistGraphQl/composer.json @@ -6,6 +6,7 @@ "php": "~7.1.3||~7.2.0", "magento/framework": "*", "magento/module-catalog": "*", + "magento/module-catalog-graph-ql": "*", "magento/module-wishlist": "*", "magento/module-store": "*" }, diff --git a/composer.lock b/composer.lock index d4ac4fc091bbc..bbc15bd96073b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "78153b5c8150c0d145b3372a534a45eb", + "content-hash": "18b533cc6fd96cad7b777d61edf94bd4", "packages": [ { "name": "braintree/braintree_php", From 7b6917c2ce5c19edc2d293a40a7c1b39b1aa1060 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Wed, 14 Nov 2018 16:48:20 +0200 Subject: [PATCH 0692/1158] MAGETWO-96222: Apply Category Permissions to Website 2 --- .../Test/Mftf/ActionGroup/AdminProductActionGroup.xml | 1 - .../Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml | 1 - .../Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml | 5 +++-- app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml | 1 + app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index dce3c72106c51..4084a2871b62f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -121,7 +121,6 @@ <argument name="simpleProduct"/> </arguments> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> - <waitForPageLoad stepKey="waitForPageLoad"/> <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> <fillField userInput="{{simpleProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml index 1bd9bb4a09c86..94400b2208b8b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml @@ -172,7 +172,6 @@ </arguments> <!--TODO use other action group for filtering grid when MQE-539 is implemented --> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> - <waitForPageLoad time="60" stepKey="waitForPageLoadInitial"/> <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{sku}}" stepKey="fillProductSkuFilter"/> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml index b21c79692a7cf..32e137c336cb3 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml @@ -10,14 +10,15 @@ <actionGroup name="AdminCreateStoreGroupActionGroup"> <arguments> <argument name="Website" defaultValue="_defaultWebsite"/> + <argument name="storeGroup" defaultValue="CustomStoreGroupCustomWebsite"/> </arguments> <amOnPage url="{{AdminSystemStoreGroupPage.url}}" stepKey="navigateToNewStoreGroup"/> <waitForPageLoad stepKey="waitForStoreGroupPageLoad" /> <comment userInput="Creating Store Group" stepKey="storeGroupCreationComment" /> <selectOption selector="{{AdminNewStoreGroupSection.storeGrpWebsiteDropdown}}" userInput="{{Website.name}}" stepKey="selectWebsite" /> - <fillField selector="{{AdminNewStoreGroupSection.storeGrpNameTextField}}" userInput="{{CustomStoreGroupCustomWebsite.name}}" stepKey="enterStoreGroupName" /> - <fillField selector="{{AdminNewStoreGroupSection.storeGrpCodeTextField}}" userInput="{{CustomStoreGroupCustomWebsite.code}}" stepKey="enterStoreGroupCode" /> + <fillField selector="{{AdminNewStoreGroupSection.storeGrpNameTextField}}" userInput="{{storeGroup.name}}" stepKey="enterStoreGroupName" /> + <fillField selector="{{AdminNewStoreGroupSection.storeGrpCodeTextField}}" userInput="{{storeGroup.code}}" stepKey="enterStoreGroupCode" /> <selectOption selector="{{AdminNewStoreGroupSection.storeRootCategoryDropdown}}" userInput="Default Category" stepKey="setRootCategory" /> <click selector="{{AdminNewStoreGroupActionsSection.saveButton}}" stepKey="clickSaveStoreGroup" /> <waitForElementVisible selector="{{AdminStoresGridSection.storeFilterTextField}}" stepKey="waitForPageReload"/> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml index 7b31623f237e9..ce8336e23fc01 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml @@ -31,4 +31,5 @@ <data key="name">NewStore</data> <data key="code">Base1</data> </entity> + <entity name="customStoreGroup2" extends="customStoreGroup" type="group"/> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml index ee137d78d7fd2..70b018907ee99 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml @@ -19,4 +19,5 @@ <data key="store_type">website</data> <data key="website_id">null</data> </entity> + <entity name="customWebsite2" extends="customWebsite" type="website"/> </entities> From c9f4db3d2421f3b3b8b648e6c9aac129cd68330b Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Wed, 14 Nov 2018 16:58:11 +0200 Subject: [PATCH 0693/1158] MAGETWO-96312: Delete Address button on customer address modal does not close and returns json --- .../Adminhtml/Edit/Address/DeleteButton.php | 32 +++++++++-- .../Controller/Adminhtml/Address/Delete.php | 3 +- .../ui_component/customer_address_form.xml | 2 +- .../adminhtml/web/js/form/components/form.js | 53 +++++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php index 8375aa13fdeff..88392139d137e 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -23,14 +23,36 @@ class DeleteButton extends GenericButton implements ButtonProviderInterface public function getButtonData() { $data = []; + $confirm = __('Are you sure you want to delete this address?'); if ($this->getAddressId()) { $data = [ 'label' => __('Delete'), - 'class' => 'delete', - 'on_click' => 'deleteConfirm(\'' . __( - 'Are you sure you want to delete this address?' - ) . '\', \'' . $this->getDeleteUrl() . '\')', - 'sort_order' => 15, + 'on_click' => '', + 'data_attribute' => [ + 'mage-init' => [ + 'Magento_Ui/js/form/button-adapter' => [ + 'actions' => [ + [ + 'targetName' => 'customer_address_form.customer_address_form', + 'actionName' => 'delete', + 'params' => [ + $this->getDeleteUrl(), + ], + + ], + [ + 'targetName' => 'customer_form.areas.address.address.customer_address_update_modal', + 'actionName' => 'closeModal' + ], + [ + 'targetName' => 'customer_address_listing.customer_address_listing', + 'actionName' => 'reload' + ] + ], + ], + ], + ], + 'sort_order' => 20 ]; } return $data; diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 65da3bca49e9b..d14cf86e4084e 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -9,6 +9,7 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; @@ -17,7 +18,7 @@ /** * Button for deletion of customer address in admin */ -class Delete extends Action implements HttpGetActionInterface +class Delete extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 4aeb7d67ace68..8e61c458fb812 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> +<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd" component="Magento_Customer/js/form/components/form"> <argument name="data" xsi:type="array"> <item name="js_config" xsi:type="array"> <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js new file mode 100644 index 0000000000000..893388a869090 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js @@ -0,0 +1,53 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'Magento_Ui/js/modal/alert', + 'Magento_Ui/js/form/form', + 'mage/translate' +], function ($, uiAlert, Form, $t) { + 'use strict'; + + return Form.extend({ + defaults: { + ajaxSettings: { + method: 'POST', + dataType: 'json' + } + }, + + /** + * Perform asynchronous DELETE request to server. + * @param {String} url - ajax url + * @returns {Deferred} + */ + delete: function (url) { + var settings = _.extend({}, this.ajaxSettings, { + url: url, + data: { + 'form_key': window.FORM_KEY + } + }); + + return $.ajax(settings) + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); + + } + }); +}); From 4c236e7e5134805ee1194a2809cc3f1ddf537cf8 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Tue, 13 Nov 2018 17:11:34 +0200 Subject: [PATCH 0694/1158] ENGCOM-3243: Fixed static test. --- .../testsuite/Magento/Framework/Interception/AbstractPlugin.php | 2 ++ .../Magento/Framework/Interception/Config/CacheManagerTest.php | 2 +- lib/internal/Magento/Framework/Interception/Config/Config.php | 2 +- .../src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php index 2a34f18fb0a0d..281a038a5a9a9 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php @@ -56,6 +56,8 @@ public function tearDown() /** * Set up Interception Config + * + * @param array $pluginConfig */ public function setUpInterceptionConfig($pluginConfig) { diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php index 6b0487d4afdae..75737f0147274 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/Config/CacheManagerTest.php @@ -40,7 +40,7 @@ protected function setUp() $this->serializer = $this->objectManager->get(\Magento\Framework\Serialize\SerializerInterface::class); $this->cache = $this->objectManager->get(\Magento\Framework\App\CacheInterface::class); - $this->configWriter = + $this->configWriter = $this->objectManager->get(\Magento\Framework\App\ObjectManager\ConfigWriter\Filesystem::class); $this->initializeMetadataDirectory(); diff --git a/lib/internal/Magento/Framework/Interception/Config/Config.php b/lib/internal/Magento/Framework/Interception/Config/Config.php index 7632970705fff..3f16e9275bd08 100644 --- a/lib/internal/Magento/Framework/Interception/Config/Config.php +++ b/lib/internal/Magento/Framework/Interception/Config/Config.php @@ -113,7 +113,7 @@ public function __construct( $this->_cacheId = $cacheId; $this->_reader = $reader; $this->_scopeList = $scopeList; - $this->cacheManager = + $this->cacheManager = $cacheManager ?? \Magento\Framework\App\ObjectManager::getInstance()->get(CacheManager::class); $intercepted = $this->cacheManager->load($cacheId); if ($intercepted !== null) { diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php index fbdbc951462e4..69de120cca49e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php @@ -48,7 +48,7 @@ protected function setUp() $this->configReaderMock = $this->getMockBuilder(\Magento\Setup\Module\Di\Compiler\Config\Reader::class) ->disableOriginalConstructor() ->getMock(); - $this->configWriterMock = + $this->configWriterMock = $this->getMockBuilder(\Magento\Framework\App\ObjectManager\ConfigWriterInterface::class) ->disableOriginalConstructor() ->getMock(); From ee50fcbca5726e4fbb120e72749e7ec9b7c45c50 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <p.bystritsky@yandex.ru> Date: Wed, 14 Nov 2018 17:13:20 +0200 Subject: [PATCH 0695/1158] ENGCOM-3449: Fixed static test. --- .../Model/ResourceModel/Db/Collection/AbstractCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php index 6e1ea24a61a4a..8ec47ed97e11c 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php @@ -177,7 +177,7 @@ public function setMainTable($table) } /** - * {@inheritdoc} + * @inheritdoc */ protected function _initSelect() { From e90bc28be176ec24b027ba05e4d74882738ac1c9 Mon Sep 17 00:00:00 2001 From: Yevhenii Dumskyi <yevhenii.dumskyi@gmail.com> Date: Wed, 14 Nov 2018 17:41:44 +0200 Subject: [PATCH 0696/1158] Fix static analysis errors --- app/code/Magento/Ui/view/base/web/js/grid/massactions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/massactions.js b/app/code/Magento/Ui/view/base/web/js/grid/massactions.js index 2e87e00fecda9..f26ca8697c2ff 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/massactions.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/massactions.js @@ -153,9 +153,9 @@ define([ var itemsType = data.excludeMode ? 'excluded' : 'selected', selections = {}; - if (itemsType === 'excluded' && data['selected'].length){ - data['selected'] = _.difference(data['selected'], data['excluded']); + if (itemsType === 'excluded' && data.selected && data.selected.length) { itemsType = 'selected'; + data[itemsType] = _.difference(data.selected, data.excluded); } selections[itemsType] = data[itemsType]; From ec040afdb5692c435d58c70914471b64216f7059 Mon Sep 17 00:00:00 2001 From: Alexandre Jardin <info@ajardin.fr> Date: Wed, 14 Nov 2018 16:35:10 +0100 Subject: [PATCH 0697/1158] Fix dependency between Elasticsearch configuration fields --- app/code/Magento/Elasticsearch/etc/adminhtml/system.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Elasticsearch/etc/adminhtml/system.xml b/app/code/Magento/Elasticsearch/etc/adminhtml/system.xml index b9fddc46f78ec..dd42b408ff75e 100644 --- a/app/code/Magento/Elasticsearch/etc/adminhtml/system.xml +++ b/app/code/Magento/Elasticsearch/etc/adminhtml/system.xml @@ -92,15 +92,15 @@ <field id="elasticsearch5_username" translate="label" type="text" sortOrder="65" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Elasticsearch HTTP Username</label> <depends> - <field id="elasticsearch_enable_auth">1</field> <field id="engine">elasticsearch5</field> + <field id="elasticsearch5_enable_auth">1</field> </depends> </field> <field id="elasticsearch5_password" translate="label" type="text" sortOrder="66" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Elasticsearch HTTP Password</label> <depends> - <field id="elasticsearch_enable_auth">1</field> <field id="engine">elasticsearch5</field> + <field id="elasticsearch5_enable_auth">1</field> </depends> </field> <field id="elasticsearch5_server_timeout" translate="label" type="text" sortOrder="67" showInDefault="1" showInWebsite="0" showInStore="0"> From 62fa0e82be34ad04bc0cc4308fd41bbd32ba34c6 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 14 Nov 2018 09:50:24 -0600 Subject: [PATCH 0698/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - converted change to be backwards compatible --- .../Model/Product/Type/Grouped.php | 94 +++++++++++++------ 1 file changed, 65 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 2f8249397819a..8fc0b856ca46d 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -10,6 +10,7 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Framework\App\ObjectManager; use Magento\CatalogInventory\Helper\Stock as StockHelper; +use \Magento\Catalog\Model\Product; /** * Grouped product type model @@ -29,6 +30,13 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ protected $_keyAssociatedProducts = '_cache_instance_associated_products'; + /** + * Cache key for Associated Products that are in stock + * + * @var string + */ + protected $_keyInStockAssociatedProducts = '_cache_instance_in_stock_associated_products'; + /** * Cache key for Associated Product Ids * @@ -205,39 +213,15 @@ public function getParentIdsByChild($childId) } /** - * Retrieve array of associated products + * Retrieve array of associated products excluding those that are out of stock * * @param \Magento\Catalog\Model\Product $product - * @param bool $includeOutOfStock * @return array */ - public function getAssociatedProducts($product, bool $includeOutOfStock = true) + public function getAssociatedProducts($product) { if (!$product->hasData($this->_keyAssociatedProducts)) { - $associatedProducts = []; - - $this->setSaleableStatus($product); - - $collection = $this->getAssociatedProductCollection( - $product - )->addAttributeToSelect( - ['name', 'price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id'] - )->addFilterByRequiredOptions()->setPositionOrder()->addStoreFilter( - $this->getStoreFilter($product) - )->addAttributeToFilter( - 'status', - ['in' => $this->getStatusFilters($product)] - ); - - if (!$includeOutOfStock) { - $this->stockHelper->addIsInStockFilterToCollection($collection); - } - - foreach ($collection as $item) { - $associatedProducts[] = $item; - } - - $product->setData($this->_keyAssociatedProducts, $associatedProducts); + $this->assignAssociatedProducts($product, true); } return $product->getData($this->_keyAssociatedProducts); } @@ -352,7 +336,9 @@ public function getAssociatedProductCollection($product) protected function getProductInfo(\Magento\Framework\DataObject $buyRequest, $product, $isStrictProcessMode) { $productsInfo = $buyRequest->getSuperGroup() ?: []; - $associatedProducts = $this->getAssociatedProducts($product, !empty($productsInfo)); + $associatedProducts = empty($productsInfo) + ? $this->getInStockAssociatedProducts($product) + : $this->getAssociatedProducts($product); if (!is_array($productsInfo)) { return __('Please specify the quantity of product(s).')->render(); @@ -391,7 +377,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p return $productsInfo; } $associatedProducts = !$isStrictProcessMode || !empty($productsInfo) - ? $this->getAssociatedProducts($product) + ? $this->getInStockAssociatedProducts($product) : false; foreach ($associatedProducts as $subProduct) { @@ -524,4 +510,54 @@ public function getChildrenMsrp(\Magento\Catalog\Model\Product $product) } return $prices ? min($prices) : 0; } + + /** + * Retrieve array of associated products that are out in stock + * + * @param \Magento\Catalog\Model\Product $product + * @return array + */ + private function getInStockAssociatedProducts($product) + { + if (!$product->hasData($this->_keyInStockAssociatedProducts)) { + $this->assignAssociatedProducts($product, false); + } + return $product->getData($this->_keyInStockAssociatedProducts); + } + + /** + * Caches associated products to the product optionally including out of stock items + * + * @param Product $product + * @param bool $includeOutOfStock + */ + private function assignAssociatedProducts(Product $product, bool $includeOutOfStock = true): void + { + $associatedProducts = []; + + $this->setSaleableStatus($product); + + $collection = $this->getAssociatedProductCollection( + $product + )->addAttributeToSelect( + ['name', 'price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id'] + )->addFilterByRequiredOptions()->setPositionOrder()->addStoreFilter( + $this->getStoreFilter($product) + )->addAttributeToFilter( + 'status', + ['in' => $this->getStatusFilters($product)] + ); + + if (!$includeOutOfStock) { + $this->stockHelper->addIsInStockFilterToCollection($collection); + } + + foreach ($collection as $item) { + $associatedProducts[] = $item; + } + + $cacheKey = $includeOutOfStock ? $this->_keyAssociatedProducts : $this->_keyInStockAssociatedProducts; + + $product->setData($cacheKey, $associatedProducts); + } } From ea3f224f63215e9ad1d109cae71243a043cb0b52 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 14 Nov 2018 09:56:26 -0600 Subject: [PATCH 0699/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Fixed description --- app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 8fc0b856ca46d..399309c9c2f19 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -213,7 +213,7 @@ public function getParentIdsByChild($childId) } /** - * Retrieve array of associated products excluding those that are out of stock + * Retrieve array of associated products including those that are out of stock * * @param \Magento\Catalog\Model\Product $product * @return array From e9e2551c43ff513d28350ba4dbeb7c89f036b781 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Wed, 14 Nov 2018 10:39:47 -0600 Subject: [PATCH 0700/1158] MAGETWO-96312: Delete Address button on customer address modal does not close and returns json --- .../Adminhtml/Edit/Address/DeleteButton.php | 10 +-- .../ui_component/customer_address_form.xml | 3 + .../adminhtml/web/js/form/components/form.js | 69 ++++++++++++------- .../web/js/form/components/insert-form.js | 8 +++ .../view/base/ui_component/customer_form.xml | 1 + 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php index 88392139d137e..7296a5167622a 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -34,19 +34,11 @@ public function getButtonData() 'actions' => [ [ 'targetName' => 'customer_address_form.customer_address_form', - 'actionName' => 'delete', + 'actionName' => 'deleteAddress', 'params' => [ $this->getDeleteUrl(), ], - ], - [ - 'targetName' => 'customer_form.areas.address.address.customer_address_update_modal', - 'actionName' => 'closeModal' - ], - [ - 'targetName' => 'customer_address_listing.customer_address_listing', - 'actionName' => 'reload' ] ], ], diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 8e61c458fb812..afe2396a9062f 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -10,6 +10,9 @@ <item name="js_config" xsi:type="array"> <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> </item> + <item name="config" xsi:type="array"> + <item name="confirmationMessage" translate="true" xsi:type="string">Are you sure you want to delete this address?</item> + </item> <item name="label" xsi:type="string" translate="true">Update Address</item> <item name="reverseMetadataMerge" xsi:type="boolean">true</item> <item name="template" xsi:type="string">templates/form/collapsible</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js index 893388a869090..34cbbfefce368 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js @@ -5,48 +5,69 @@ define([ 'jquery', 'Magento_Ui/js/modal/alert', + 'Magento_Ui/js/modal/confirm', 'Magento_Ui/js/form/form', 'mage/translate' -], function ($, uiAlert, Form, $t) { +], function ($, uiAlert, uiConfirm, Form, $t) { 'use strict'; return Form.extend({ defaults: { + confirmationMessage: '', ajaxSettings: { - method: 'POST', - dataType: 'json' + method: 'POST', + dataType: 'json' } }, + deleteAddress: function (url) { + var that = this; + + uiConfirm({ + content: this.confirmationMessage, + actions: { + /** @inheritdoc */ + confirm: function () { + that._delete(url); + } + } + }); + }, + /** * Perform asynchronous DELETE request to server. * @param {String} url - ajax url * @returns {Deferred} */ - delete: function (url) { + _delete: function (url) { var settings = _.extend({}, this.ajaxSettings, { - url: url, - data: { - 'form_key': window.FORM_KEY - } - }); + url: url, + data: { + 'form_key': window.FORM_KEY + } + }), + that = this; + + $('body').trigger('processStart'); return $.ajax(settings) - .done(function (response) { - if (response.error) { - uiAlert({ - content: response.message - }); - } - }) - .fail(function () { - uiAlert({ - content: $t('Sorry, there has been an error processing your request. Please try again later.') - }); - }) - .always(function () { - $('body').trigger('processStop'); - }); + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } else { + that.trigger('deleteAddressAction', that.source.get('data.entity_id')); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); } }); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js index 25303899894c4..59c3e8e4b8b0b 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -50,6 +50,14 @@ define([ ) { this.source.set('data.default_shipping_address', []); } + }, + + onAddressDelete: function (id) { + this.addressModal().closeModal(); + this.addressListing().reload({ + refresh: true + }); + this.addressListing()._delete([parseFloat(id)]); } }); }); diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index d6d61c892e00d..a7c55da2cca2f 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -467,6 +467,7 @@ </exports> <imports> <link name="parentId">${ $.provider}:data.customer_id</link> + <link name="onAddressDelete">${ $.ns }.${ $.ns }:deleteAddressAction</link> </imports> </settings> </insertForm> From 9b3fe43f891d174ed00b7dd31306d3ef71a6c7dd Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Mon, 12 Nov 2018 14:00:10 -0600 Subject: [PATCH 0701/1158] MC-5595: Magento\FunctionalTestingFramework.functional.StorefrontTaxQuoteCartLoggedInSimple fails randomly unskip mftf test --- .../Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml index 0b2809dfc3543..0326a4cadb537 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml @@ -17,9 +17,6 @@ <severity value="CRITICAL"/> <testCaseId value="MC-295"/> <group value="Tax"/> - <skip> - <issueId value="MAGETWO-96194"/> - </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> From b47df3b1f3df6ae2cb53c5f1d1b18b090386d642 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Wed, 14 Nov 2018 11:31:10 -0600 Subject: [PATCH 0702/1158] MC-5595: Magento\FunctionalTestingFramework.functional.StorefrontTaxQuoteCartLoggedInSimple fails randomly - add wait for correct shipping amount --- .../Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml index 0326a4cadb537..a41f00c547a9a 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml @@ -94,6 +94,7 @@ <waitForPageLoad stepKey="waitForCart"/> <waitForElementVisible stepKey="waitForOverviewVisible" selector="{{CheckoutPaymentSection.tax}}"/> + <waitForElementVisible stepKey="waitForCorrectShippingAmount" selector="{{CheckoutPaymentSection.orderSummaryShippingTotal}}[text()='$5.00']"/> <see stepKey="seeTax" selector="{{CheckoutPaymentSection.tax}}" userInput="$10.30"/> <click stepKey="expandTax" selector="{{CheckoutPaymentSection.tax}}"/> <see stepKey="seeTaxPercent" selector="{{CheckoutPaymentSection.taxPercentage}}" userInput="({{SimpleTaxNY.rate}}%)"/> From b05611c12ee10bfc2268a1dd14398fe756dc8a04 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 14 Nov 2018 12:07:28 -0600 Subject: [PATCH 0703/1158] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Marked new property as private --- .../GroupedProduct/Model/Product/Type/Grouped.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 399309c9c2f19..0bbadaa1ba869 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -30,13 +30,6 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ protected $_keyAssociatedProducts = '_cache_instance_associated_products'; - /** - * Cache key for Associated Products that are in stock - * - * @var string - */ - protected $_keyInStockAssociatedProducts = '_cache_instance_in_stock_associated_products'; - /** * Cache key for Associated Product Ids * @@ -101,6 +94,13 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ private $stockHelper; + /** + * Cache key for Associated Products that are in stock + * + * @var string + */ + private $_keyInStockAssociatedProducts = '_cache_instance_in_stock_associated_products'; + /** * @param \Magento\Catalog\Model\Product\Option $catalogProductOption * @param \Magento\Eav\Model\Config $eavConfig From 0266f59a2d7a4a75bb27804f5f5eebfadeb46919 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Wed, 14 Nov 2018 13:32:44 -0600 Subject: [PATCH 0704/1158] MAGETWO-95892: Selecting Gift Options for items redirects on 404 Page - Resolve static test failures --- app/code/Magento/Checkout/Controller/Cart/UpdatePost.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php index be84dcd76bb88..5727447b3a527 100644 --- a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php +++ b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,6 +9,9 @@ use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\Action\HttpGetActionInterface; +/** + * Class UpdatePost + */ class UpdatePost extends \Magento\Checkout\Controller\Cart implements HttpPostActionInterface, HttpGetActionInterface { /** From 31adbdbfa226f96fb1e98353645a206cc8e15c43 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Wed, 14 Nov 2018 15:00:47 -0600 Subject: [PATCH 0705/1158] MC-5538: Search terms are not cached in case of form_key present in the request --- .../Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml | 1 + lib/web/mage/common.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml b/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml index 7ca86b8b14a4d..387a7547f4daf 100644 --- a/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml +++ b/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml @@ -15,6 +15,7 @@ </arguments> <submitForm selector="#search_mini_form" parameterArray="['q' => '{{phrase}}']" stepKey="fillQuickSearch" /> <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl"/> + <dontSeeInCurrentUrl url="form_key=" stepKey="checkUrlFormKey"/> <seeInTitle userInput="Search results for: '{{phrase}}'" stepKey="assertQuickSearchTitle"/> <see userInput="Search results for: '{{phrase}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName"/> </actionGroup> diff --git a/lib/web/mage/common.js b/lib/web/mage/common.js index 4742c77ea8627..01f696ec1b7fc 100644 --- a/lib/web/mage/common.js +++ b/lib/web/mage/common.js @@ -21,7 +21,7 @@ define([ form = $(e.target), formKey = $('input[name="form_key"]').val(); - if (formKey && !form.find('input[name="form_key"]').length) { + if (formKey && !form.find('input[name="form_key"]').length && form[0].method !== 'get') { formKeyElement = document.createElement('input'); formKeyElement.setAttribute('type', 'hidden'); formKeyElement.setAttribute('name', 'form_key'); From 0a12f2facafd2eaea06a208173cf1e564e107a19 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Wed, 14 Nov 2018 18:00:59 -0600 Subject: [PATCH 0706/1158] ENGCOM-3450: [Forwardport] Fixed tierprice discount not calculated correctly if has specialprice #19179 --- .../Catalog/Model/Product/Attribute/Backend/Tierprice.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index 23b2dfa01bfbd..e346c912dccaa 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -13,6 +13,9 @@ use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; +/** + * Backend model for Tierprice attribute + */ class Tierprice extends \Magento\Catalog\Model\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice { /** @@ -186,6 +189,10 @@ protected function modifyPriceData($object, $data) } /** + * Update Price values in DB + * + * Updates price values in DB from array comparing to old values. Returns bool if updated + * * @param array $valuesToUpdate * @param array $oldValues * @return boolean From bd5456f00d2458c5a9f1f6a6446bec66f3ea7f2e Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Nov 2018 08:49:48 +0200 Subject: [PATCH 0707/1158] MAGETWO-96222: Apply Category Permissions to Website 2 --- ...upActionGroup.xml => AdminStoreGroupCreateActionGroup.xml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename app/code/Magento/Store/Test/Mftf/ActionGroup/{AdminCreateStoreGroupActionGroup.xml => AdminStoreGroupCreateActionGroup.xml} (91%) diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminStoreGroupCreateActionGroup.xml similarity index 91% rename from app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml rename to app/code/Magento/Store/Test/Mftf/ActionGroup/AdminStoreGroupCreateActionGroup.xml index 32e137c336cb3..023d5fc3587fb 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminStoreGroupCreateActionGroup.xml @@ -7,10 +7,10 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminCreateStoreGroupActionGroup"> + <actionGroup name="AdminStoreGroupCreateActionGroup"> <arguments> <argument name="Website" defaultValue="_defaultWebsite"/> - <argument name="storeGroup" defaultValue="CustomStoreGroupCustomWebsite"/> + <argument name="storeGroup"/> </arguments> <amOnPage url="{{AdminSystemStoreGroupPage.url}}" stepKey="navigateToNewStoreGroup"/> <waitForPageLoad stepKey="waitForStoreGroupPageLoad" /> From 252b19901b6eef8b9f339b3a8581972bb1114258 Mon Sep 17 00:00:00 2001 From: Danny Verkade <danny@cream.nl> Date: Thu, 15 Nov 2018 11:20:45 +0100 Subject: [PATCH 0708/1158] - Removed hard coded precision in PriceCurrency class. - PriceCurrency now uses the DEFAULT_PRECISION constant for rounding. - Cleanup convertAndRound function, so rounding only takes place in one function. --- app/code/Magento/Directory/Model/PriceCurrency.php | 13 ++++--------- .../Framework/Pricing/PriceCurrencyInterface.php | 3 ++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Directory/Model/PriceCurrency.php b/app/code/Magento/Directory/Model/PriceCurrency.php index a211242d377f3..0d8c7a40f8249 100644 --- a/app/code/Magento/Directory/Model/PriceCurrency.php +++ b/app/code/Magento/Directory/Model/PriceCurrency.php @@ -62,9 +62,7 @@ public function convert($amount, $scope = null, $currency = null) */ public function convertAndRound($amount, $scope = null, $currency = null, $precision = self::DEFAULT_PRECISION) { - $currentCurrency = $this->getCurrency($scope, $currency); - $convertedValue = $this->getStore($scope)->getBaseCurrency()->convert($amount, $currentCurrency); - return round($convertedValue, $precision); + return $this->round($this->convert($amount, $scope, $currency), $precision); } /** @@ -148,13 +146,10 @@ protected function getStore($scope = null) } /** - * Round price - * - * @param float $price - * @return float + * {@inheritdoc} */ - public function round($price) + public function round($price, $precision = self::DEFAULT_PRECISION) { - return round($price, 2); + return round($price, $precision); } } diff --git a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php index 31f00d8b1345a..f3bad28b5011a 100644 --- a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php +++ b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php @@ -79,9 +79,10 @@ public function convertAndFormat( * Round price * * @param float $price + * @param int $precision * @return float */ - public function round($price); + public function round($price, $precision = self::DEFAULT_PRECISION); /** * Get currency model From 4ad77022371d7572dfb8944f46e5c1dab11722e2 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Nov 2018 02:52:34 -0800 Subject: [PATCH 0709/1158] MAGETWO-96222: Apply Category Permissions to Website 2 --- .../Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml | 2 +- app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml | 1 - app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml | 5 ++++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml index 9349e188430f4..f7d8abf8b2fea 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml @@ -8,7 +8,7 @@ <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> - <page name="AdminCategoryPage" url="catalog/category/" area="admin" module="Catalog"> + <page name="AdminCategoryPage" url="catalog/category/" area="admin" module="Magento_Catalog"> <section name="AdminCategorySidebarActionSection"/> <section name="AdminCategoryMainActionsSection"/> <section name="AdminCategorySidebarTreeSection"/> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml index ce8336e23fc01..7b31623f237e9 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml @@ -31,5 +31,4 @@ <data key="name">NewStore</data> <data key="code">Base1</data> </entity> - <entity name="customStoreGroup2" extends="customStoreGroup" type="group"/> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml index 70b018907ee99..c1a8a552c3a97 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml @@ -19,5 +19,8 @@ <data key="store_type">website</data> <data key="website_id">null</data> </entity> - <entity name="customWebsite2" extends="customWebsite" type="website"/> + <entity name="secondCustomWebsite" extends="customWebsite" type="website"> + <data key="name" unique="suffix">Second Custom Website</data> + <data key="code" unique="suffix">second_custom_website</data> + </entity> </entities> From 03f0861a1be43c9d283c64ad31b804b715997d3a Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Thu, 15 Nov 2018 16:03:08 +0300 Subject: [PATCH 0710/1158] MAGETWO-71022: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value - Stabilize test --- .../Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml index 00f290cd94e70..11d973d1e19de 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormAccountSection.xml @@ -13,6 +13,6 @@ <element name="email" type="input" selector="#email"/> <element name="requiredGroup" type="text" selector=".admin__field.required[data-ui-id='billing-address-fieldset-element-form-field-group-id']"/> <element name="requiredEmail" type="text" selector=".admin__field.required[data-ui-id='billing-address-fieldset-element-form-field-email']"/> - <element name="defaultGeneral" type="text" selector="//*[text()='Default (General)']" time="15"/> + <element name="defaultGeneral" type="text" selector="//*[contains(text(),'General')]" time="15"/> </section> </sections> \ No newline at end of file From f8cbd49653e93a17a7d9a3997f0ea8d5b79aa48f Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Thu, 15 Nov 2018 15:14:41 +0200 Subject: [PATCH 0711/1158] GraphQL-43: [Query] My Account > My Wish List --- .../Magento/WishlistGraphQl/composer.json | 1 - .../WishlistGraphQl/etc/schema.graphqls | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/WishlistGraphQl/composer.json b/app/code/Magento/WishlistGraphQl/composer.json index e0f342174f879..630ee97acc2eb 100644 --- a/app/code/Magento/WishlistGraphQl/composer.json +++ b/app/code/Magento/WishlistGraphQl/composer.json @@ -5,7 +5,6 @@ "require": { "php": "~7.1.3||~7.2.0", "magento/framework": "*", - "magento/module-catalog": "*", "magento/module-catalog-graph-ql": "*", "magento/module-wishlist": "*", "magento/module-store": "*" diff --git a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls index a63ec6eff6f5b..f5b5034fb734f 100644 --- a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls @@ -2,21 +2,21 @@ # See COPYING.txt for license details. type Query { - wishlist: WishlistOutput @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistResolver") @doc(description: "todo") + wishlist: WishlistOutput @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistResolver") @doc(description: "The wishlist query returns the contents of a customer's wish list") } type WishlistOutput { - items: [WishlistItem] @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsResolver") @doc(description: "todo"), - items_count: Int @doc(description: "todo"), - name: String @doc(description: "todo"), - sharing_code: String @doc(description: "todo"), - updated_at: String @doc(description: "todo") + items: [WishlistItem] @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsResolver") @doc(description: "An array of items in the customer's wish list"), + items_count: Int @doc(description: "The number of items in the wish list"), + name: String @doc(description: "When multiple wish lists are enabled, the name the customer assigns to the wishlist"), + sharing_code: String @doc(description: "An encrypted code that Magento uses to link to the wish list"), + updated_at: String @doc(description: "The time of the last modification to the wish list") } type WishlistItem { - id: Int @doc(description: "todo") - qty: Float @doc(description: "todo"), - description: String @doc(description: "todo"), - added_at: String @doc(description: "todo"), + id: Int @doc(description: "The wish list item ID") + qty: Float @doc(description: "The quantity of this wish list item"), + description: String @doc(description: "The customer's comment about this item"), + added_at: String @doc(description: "The time when the customer added the item to the wish list"), product: ProductInterface @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\ProductResolver") } \ No newline at end of file From 31797246faf847433f9353ec61375f3adb51e531 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Thu, 15 Nov 2018 15:29:20 +0200 Subject: [PATCH 0712/1158] GraphQL-43: [Query] My Account > My Wish List - Update composer files --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 7ce9efeb65e6f..0af9477ff4ef9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "243bbfba7578f2084615fa0c092f87a8", + "content-hash": "b367db394f87f9f9006b40e36e5a4175", "packages": [ { "name": "braintree/braintree_php", From 715ae96da3204d41be0590c9dcada03b8f8892f3 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Nov 2018 06:10:19 -0800 Subject: [PATCH 0713/1158] MAGETWO-96222: Apply Category Permissions to Website 2 --- app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml index c1a8a552c3a97..f636336524f01 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml @@ -19,8 +19,8 @@ <data key="store_type">website</data> <data key="website_id">null</data> </entity> - <entity name="secondCustomWebsite" extends="customWebsite" type="website"> - <data key="name" unique="suffix">Second Custom Website</data> - <data key="code" unique="suffix">second_custom_website</data> + <entity name="secondCustomWebsite" extends="customWebsite"> + <data key="name" unique="suffix">Custom Website</data> + <data key="code" unique="suffix">custom_website</data> </entity> </entities> From 52c5fba5b765dec8582ea527ce745fe77b7d2634 Mon Sep 17 00:00:00 2001 From: Stsiapan Korf <Stsiapan_Korf@epam.com> Date: Thu, 15 Nov 2018 13:24:42 +0300 Subject: [PATCH 0714/1158] MAGETWO-91496: Instantiating WYSIWYG in DynamicRows - Create parameter for suffix adding --- .../Magento/Ui/view/base/web/js/form/element/wysiwyg.js | 8 ++++++++ .../Magento/Framework/Data/Form/Element/Editor.php | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js index 235113b389fc7..070761fff53e3 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js @@ -80,6 +80,14 @@ define([ return config.name.replace(/(\.|-)/g, '_'); }, + /** + * @inheritdoc + */ + destroy: function () { + this._super(); + wysiwyg.removeEvents(this.wysiwygId); + }, + /** * * @returns {exports} diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php index dee0b6c842f5f..b5f2017501c01 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php @@ -548,6 +548,7 @@ protected function getInlineJs($jsSetupObject, $forceLoad) */ public function getHtmlId() { - return parent::getHtmlId() . '${ $.wysiwygUniqueSuffix }'; + $suffix = $this->getConfig('dynamic_id') ? '${ $.wysiwygUniqueSuffix }' : ''; + return parent::getHtmlId() . $suffix; } } From d15cca6755976100b4559351594bd5fa8f22d832 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Thu, 15 Nov 2018 15:32:22 +0200 Subject: [PATCH 0715/1158] MAGETWO-96312: Delete Address button on customer address modal does not close and returns json --- .../Adminhtml/Edit/Address/DeleteButton.php | 3 +- .../Controller/Adminhtml/Address/Delete.php | 1 - .../Edit/Address/DeleteButtonTest.php | 106 ++++++++++++++++++ .../ui_component/customer_address_form.xml | 2 +- .../adminhtml/web/js/form/components/form.js | 11 +- .../web/js/form/components/insert-form.js | 6 + .../js/view/form/components/form.test.js | 71 ++++++++++++ 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php create mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php index 7296a5167622a..da589a25df28e 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -23,7 +23,6 @@ class DeleteButton extends GenericButton implements ButtonProviderInterface public function getButtonData() { $data = []; - $confirm = __('Are you sure you want to delete this address?'); if ($this->getAddressId()) { $data = [ 'label' => __('Delete'), @@ -56,7 +55,7 @@ public function getButtonData() * @return string * @throws \Magento\Framework\Exception\LocalizedException */ - public function getDeleteUrl(): string + private function getDeleteUrl(): string { return $this->getUrl( Actions::CUSTOMER_ADDRESS_PATH_DELETE, diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index d14cf86e4084e..711cd2473cdc5 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,7 +8,6 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; diff --git a/app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php b/app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php new file mode 100644 index 0000000000000..7b0da3bd422a6 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php @@ -0,0 +1,106 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Unit\Block\Adminhtml\Edit\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Class for \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton unit tests + */ +class DeleteButtonTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Customer\Model\AddressFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressFactory; + + /** + * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $urlBuilder; + + /** + * @var \Magento\Customer\Model\ResourceModel\Address|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressResourceModel; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $request; + + /** + * @var \Magento\Customer\Model\ResourceModel\AddressRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressRepository; + + /** + * @var \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton + */ + private $deleteButton; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->addressFactory = $this->getMockBuilder(\Magento\Customer\Model\AddressFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->urlBuilder = $this->getMockForAbstractClass(\Magento\Framework\UrlInterface::class); + $this->addressResourceModel = $this->getMockBuilder(\Magento\Customer\Model\ResourceModel\Address::class) + ->disableOriginalConstructor() + ->getMock(); + $this->request = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class); + $this->addressRepository = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\AddressRepository::class + ) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + + $this->deleteButton = $objectManagerHelper->getObject( + \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton::class, + [ + 'addressFactory' => $this->addressFactory, + 'urlBuilder' => $this->urlBuilder, + 'addressResourceModel' => $this->addressResourceModel, + 'request' => $this->request, + 'addressRepository' => $this->addressRepository, + ] + ); + } + + /** + * Unit test for \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton::getButtonData() method + */ + public function testGetButtonData() + { + $addressId = 1; + $customerId = 2; + + /** @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->disableOriginalConstructor() + ->getMock(); + $address->expects($this->atLeastOnce())->method('getEntityId')->willReturn($addressId); + $address->expects($this->atLeastOnce())->method('getCustomerId')->willReturn($customerId); + $this->addressFactory->expects($this->atLeastOnce())->method('create')->willReturn($address); + $this->request->expects($this->atLeastOnce())->method('getParam')->with('entity_id') + ->willReturn($addressId); + $this->addressResourceModel->expects($this->atLeastOnce())->method('load')->with($address, $addressId); + $this->addressRepository->expects($this->atLeastOnce())->method('getById')->with($addressId) + ->willReturn($address); + $this->urlBuilder->expects($this->atLeastOnce())->method('getUrl') + ->with( + \Magento\Customer\Ui\Component\Listing\Address\Column\Actions::CUSTOMER_ADDRESS_PATH_DELETE, + ['parent_id' => $customerId, 'id' => $addressId] + )->willReturn('url'); + + $buttonData = $this->deleteButton->getButtonData(); + $this->assertEquals('Delete', (string)$buttonData['label']); + } +} diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index afe2396a9062f..fdef0e959443b 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -11,7 +11,7 @@ <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> </item> <item name="config" xsi:type="array"> - <item name="confirmationMessage" translate="true" xsi:type="string">Are you sure you want to delete this address?</item> + <item name="deleteConfirmationMessage" translate="true" xsi:type="string">Are you sure you want to delete this address?</item> </item> <item name="label" xsi:type="string" translate="true">Update Address</item> <item name="reverseMetadataMerge" xsi:type="boolean">true</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js index 34cbbfefce368..e1c5f01c731a0 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js @@ -13,18 +13,25 @@ define([ return Form.extend({ defaults: { - confirmationMessage: '', + deleteConfirmationMessage: '', ajaxSettings: { method: 'POST', dataType: 'json' } }, + /** + * Delete customer address by provided url. + * Will call confirmation message to be sure that user is really wants to delete this address + * + * @param {String} url - ajax url + */ deleteAddress: function (url) { + console.log(url); var that = this; uiConfirm({ - content: this.confirmationMessage, + content: this.deleteConfirmationMessage, actions: { /** @inheritdoc */ confirm: function () { diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js index 59c3e8e4b8b0b..45d0ff112f096 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -52,6 +52,12 @@ define([ } }, + /** + * Event method that closes "Edit customer address" modal and refreshes grid after customer address + * was removed through "Delete" button on the "Edit customer address" modal + * + * @param {string} id - customer address ID to delete + */ onAddressDelete: function (id) { this.addressModal().closeModal(); this.addressListing().reload({ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js new file mode 100644 index 0000000000000..99ce913e87390 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js @@ -0,0 +1,71 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'uiRegistry', + 'Magento_Customer/js/form/components/form', + 'jquery' +], function (_, registry, Constr, $) { + 'use strict'; + + describe('Magento_Customer/js/form/components/form', function () { + + var obj, + originaljQueryAjax; + + beforeEach (function () { + originaljQueryAjax = $.ajax; + obj = new Constr({ + provider: 'provName', + name: '', + index: '' + }); + }); + + afterEach(function () { + $.ajax = originaljQueryAjax; + }); + + registry.set('provName', { + /** Stub */ + on: function () {}, + + /** Stub */ + get: function () {}, + + /** Stub */ + set: function () {} + }); + + describe('"deleteAddress" method', function () { + it('Check for defined ', function () { + expect(obj.hasOwnProperty('deleteAddress')).toBeDefined(); + }); + it('Check method type', function () { + var type = typeof obj.deleteAddress; + + expect(type).toEqual('function'); + }); + it('Check returned value if method called without arguments', function () { + expect(obj.deleteAddress()).toBeUndefined(); + }); + it('Check returned value type if method called without arguments', function () { + var type = typeof obj.deleteAddress(); + + expect(type).toEqual('undefined'); + }); + it('Should call not call ajax if arguments are empty', function () { + $.ajax = jasmine.createSpy(); + + spyOn(obj, 'deleteAddress'); + + expect(obj.deleteAddress()).toBeUndefined(); + + expect($.ajax).not.toHaveBeenCalled(); + }); + }); + }); +}); From adda7da9743ef8eb90f1d060e72d65bcdc7d0b40 Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Thu, 15 Nov 2018 08:59:26 -0600 Subject: [PATCH 0716/1158] Revert "MQE-1267: Unskip Timezone Tests in Magento 2.3" - This reverts commit 0e0c110 --- .../Test/AdminApplyCatalogRuleByCategoryTest.xml | 3 +++ .../Mftf/Test/AdminCreateCatalogPriceRuleTest.xml | 15 +++++++++++++++ .../Mftf/Test/AdminDeleteCatalogPriceRuleTest.xml | 3 +++ .../Test/StorefrontInactiveCatalogRuleTest.xml | 3 +++ 4 files changed, 24 insertions(+) diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminApplyCatalogRuleByCategoryTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminApplyCatalogRuleByCategoryTest.xml index 741da96179b8c..716a363ec5d78 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminApplyCatalogRuleByCategoryTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminApplyCatalogRuleByCategoryTest.xml @@ -16,6 +16,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-74"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <createData entity="ApiCategory" stepKey="createCategoryOne"/> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml index befe0b0ce7f98..072385c46645a 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml @@ -17,6 +17,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-65"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <!-- Create the simple product and category that it will be in --> @@ -74,6 +77,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-93"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"> @@ -97,6 +103,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-69"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"> @@ -120,6 +129,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-60"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"> @@ -143,6 +155,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-71"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <!-- Create a simple product and a category--> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminDeleteCatalogPriceRuleTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminDeleteCatalogPriceRuleTest.xml index d3546d06492be..83770ffff5eab 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminDeleteCatalogPriceRuleTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminDeleteCatalogPriceRuleTest.xml @@ -17,6 +17,9 @@ <severity value="MAJOR"/> <testCaseId value="MC-160"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml index e7be6e8443a36..55f775e40feaa 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml @@ -17,6 +17,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-79"/> <group value="CatalogRule"/> + <skip> + <issueId value="DEVOPS-3618"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="login"/> From db851ff49c3e8e6c49dce7d10c0a56a57020f9c4 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Thu, 15 Nov 2018 17:35:20 +0200 Subject: [PATCH 0717/1158] GraphQL-43: [Query] My Account > My Wish List - Update composer files --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 2e1b77fe0a3c9..36b4dca023191 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4f2fd2e8ffcc003e0a4a4116ec84b780", + "content-hash": "7538e15ea4ff1378cf55983ce9acba82", "packages": [ { "name": "braintree/braintree_php", From 0154cf538f0129ab3578bb0506ee9c820baf505b Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 15 Nov 2018 09:51:20 -0600 Subject: [PATCH 0718/1158] MC-5535: Numbers mismatch between the products displayed and the product count on Category structure - Fixed condition and added assertions --- .../Catalog/Model/ResourceModel/Category/Collection.php | 6 +----- ...AdminFilteringCategoryProductsUsingScopeSelectorTest.xml | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php index 46bb74513b59c..4562aa0b0e75f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php @@ -322,11 +322,7 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr ['e' => $this->getTable('catalog_category_entity')], 'main_table.category_id=e.entity_id', [] - )->where( - 'e.entity_id = :entity_id' - )->orWhere( - 'e.path LIKE :c_path' - ); + )->where('e.entity_id = :entity_id OR e.path LIKE :c_path'); if ($websiteId) { $select->join( ['w' => $this->getProductWebsiteTable()], diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml index a748635ac9a53..9e323745835c2 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml @@ -140,6 +140,7 @@ userInput="$$createProduct1.name$$" stepKey="seeProductName4"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct12.name$$)}}" userInput="$$createProduct12.name$$" stepKey="seeProductName5"/> + <waitForText userInput="$$createCategory.name$$ (2)" stepKey="seeCorrectProductCount"/> <dontSee selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct0.name$$)}}" userInput="$$createProduct0.name$$" stepKey="dontSeeProductName"/> <dontSee selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct2.name$$)}}" @@ -164,6 +165,7 @@ userInput="$$createProduct2.name$$" stepKey="seeProductName6"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct12.name$$)}}" userInput="$$createProduct12.name$$" stepKey="seeProductName7"/> + <waitForText userInput="$$createCategory.name$$ (2)" stepKey="seeCorrectProductCount2"/> <dontSee selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct0.name$$)}}" userInput="$$createProduct0.name$$" stepKey="dontSeeProductName2"/> <dontSee selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct2.name$$)}}" From a0a150fce54acdbb6fc8fc85820972cd33ebdaa9 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Thu, 15 Nov 2018 12:00:53 -0600 Subject: [PATCH 0719/1158] #2340: Fixed static tests --- .../Magento/Bundle/Model/OptionRepository.php | 20 +++++++++++++------ .../Test/Unit/Model/OptionRepositoryTest.php | 3 ++- .../product_grouped_with_out_of_stock.php | 2 +- ...uct_grouped_with_out_of_stock_rollback.php | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Bundle/Model/OptionRepository.php b/app/code/Magento/Bundle/Model/OptionRepository.php index 46c44c83b5bb5..0b96ea8d5b789 100644 --- a/app/code/Magento/Bundle/Model/OptionRepository.php +++ b/app/code/Magento/Bundle/Model/OptionRepository.php @@ -90,7 +90,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function get($sku, $optionId) { @@ -123,7 +123,7 @@ public function get($sku, $optionId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getList($sku) { @@ -132,6 +132,8 @@ public function getList($sku) } /** + * Return list of product options + * * @param ProductInterface $product * @return \Magento\Bundle\Api\Data\OptionInterface[] */ @@ -141,7 +143,7 @@ public function getListByProduct(ProductInterface $product) } /** - * {@inheritdoc} + * @inheritdoc */ public function delete(\Magento\Bundle\Api\Data\OptionInterface $option) { @@ -157,7 +159,7 @@ public function delete(\Magento\Bundle\Api\Data\OptionInterface $option) } /** - * {@inheritdoc} + * @inheritdoc */ public function deleteById($sku, $optionId) { @@ -169,7 +171,7 @@ public function deleteById($sku, $optionId) } /** - * {@inheritdoc} + * @inheritdoc */ public function save( \Magento\Catalog\Api\Data\ProductInterface $product, @@ -189,6 +191,9 @@ public function save( * @param \Magento\Catalog\Api\Data\ProductInterface $product * @param \Magento\Bundle\Api\Data\OptionInterface $option * @return $this + * @throws InputException + * @throws NoSuchEntityException + * @throws \Magento\Framework\Exception\CouldNotSaveException */ protected function updateOptionSelection( \Magento\Catalog\Api\Data\ProductInterface $product, @@ -228,9 +233,12 @@ protected function updateOptionSelection( } /** + * Retrieve product by SKU + * * @param string $sku * @return \Magento\Catalog\Api\Data\ProductInterface - * @throws \Magento\Framework\Exception\InputException + * @throws InputException + * @throws NoSuchEntityException */ private function getProduct($sku) { diff --git a/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php b/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php index c579d8289d1b6..2450f63c38933 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php @@ -280,7 +280,8 @@ public function testDeleteById() /** * Tests if NoSuchEntityException thrown when provided $optionId not found */ - public function testDeleteByIdException() { + public function testDeleteByIdException() + { $productSku = 'sku'; $optionId = null; diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php index 7aa62b149b8c0..369ce7d490eea 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock.php @@ -1,4 +1,4 @@ -\<?php +<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php index 48e7d495f8985..26a7487077e44 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_out_of_stock_rollback.php @@ -1,4 +1,4 @@ -\<?php +<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. From 408c1350a829b52f7996ce9694fa2d0f56dc6710 Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu <dzmitry_tabusheu@epam.com> Date: Fri, 16 Nov 2018 10:53:13 +0300 Subject: [PATCH 0720/1158] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Fixed functional test --- .../Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml index 1063f2aa5bf5b..272ab1dceb484 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml @@ -74,7 +74,6 @@ <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToTaxConfigPage"/> <conditionalClick stepKey="clickOrdersInvoicesCreditSales" selector="{{AdminConfigureTaxSection.taxClasses}}" dependentSelector="{{AdminConfigureTaxSection.taxClassesCondition}}" visible="false"/> <selectOption selector="{{AdminConfigureTaxSection.productTaxClass}}" userInput="Taxable Goods" stepKey="selectClass"/> - <click selector="{{AdminConfigureTaxSection.useSystemValue}}" stepKey="UncheckUseSystemValue"/> <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> <!-- Go to the tax rule page and delete the row we created--> <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> From 5ef851a596363d40ed259d10f10299a43b6891bf Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Fri, 16 Nov 2018 10:30:35 +0200 Subject: [PATCH 0721/1158] =?UTF-8?q?ENGCOM-3435:=2019082-Fatal-error-Unca?= =?UTF-8?q?ught-Error-Cannot-call-abstract-method-Magento-=E2=80=A6=20#191?= =?UTF-8?q?55=20Fix=20static=20tests.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Magento/Catalog/Controller/Product/Compare.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Product/Compare.php b/app/code/Magento/Catalog/Controller/Product/Compare.php index 63478080bce1a..084a82f87d645 100644 --- a/app/code/Magento/Catalog/Controller/Product/Compare.php +++ b/app/code/Magento/Catalog/Controller/Product/Compare.php @@ -6,6 +6,7 @@ namespace Magento\Catalog\Controller\Product; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Data\Form\FormKey\Validator; use Magento\Framework\View\Result\PageFactory; @@ -15,7 +16,7 @@ * @SuppressWarnings(PHPMD.LongVariable) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -abstract class Compare extends \Magento\Framework\App\Action\Action +abstract class Compare extends \Magento\Framework\App\Action\Action implements HttpGetActionInterface { /** * Customer id @@ -141,11 +142,13 @@ public function setCustomerId($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function execute() { - return $this->_redirect('catalog/product_compare'); - } + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setPath('catalog/product_compare'); + return $resultRedirect; + } } From b7c25f3f60649c7f4f2f47e46d13a6f94aba552f Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Fri, 16 Nov 2018 16:23:12 +0200 Subject: [PATCH 0722/1158] GraphQL-43: [Query] My Account > My Wish List -- Fix static tests --- .../WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php | 2 ++ app/code/Magento/WishlistGraphQl/registration.php | 1 + 2 files changed, 3 insertions(+) diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php index 033c63441e907..dfbbf6543f66f 100644 --- a/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItemsResolver.php @@ -77,6 +77,8 @@ public function resolve( } /** + * Get wishlist items + * * @param Wishlist $wishlist * @return Item[] */ diff --git a/app/code/Magento/WishlistGraphQl/registration.php b/app/code/Magento/WishlistGraphQl/registration.php index f2047f225e5b6..c5d468421f96e 100644 --- a/app/code/Magento/WishlistGraphQl/registration.php +++ b/app/code/Magento/WishlistGraphQl/registration.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); use Magento\Framework\Component\ComponentRegistrar; From ef2cf53a60cc7a60895685230c8ad52181de0c3e Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Fri, 16 Nov 2018 16:26:41 +0200 Subject: [PATCH 0723/1158] MAGETWO-96330: Default Shipping Address Edit button is displayed incorrectly --- .../ui_component/customer_address_form.xml | 4 +- .../web/template/default-address-wrapper.html | 7 + .../view/base/ui_component/customer_form.xml | 185 +++++++++--------- .../web/css/source/_module.less | 27 +-- 4 files changed, 111 insertions(+), 112 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index fdef0e959443b..e07c5d97a30a6 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -80,7 +80,7 @@ <dataType>text</dataType> </settings> </field> - <field name="default_billing" sortOrder="6" formElement="checkbox"> + <field name="default_billing" sortOrder="5" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> @@ -103,7 +103,7 @@ </checkbox> </formElements> </field> - <field name="default_shipping" sortOrder="5" formElement="checkbox"> + <field name="default_shipping" sortOrder="7" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html new file mode 100644 index 0000000000000..2af366b03342c --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html @@ -0,0 +1,7 @@ +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="customer-default-address-wrapper" each="data: elems, as: 'element'" render=""/> diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index a7c55da2cca2f..aabbbc09de1fb 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -312,105 +312,106 @@ <class name="customer-address-form">true</class> </additionalClasses> </settings> - <component name="customer_default_billing_address_content" template="Magento_Customer/default-address"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="defaultAddressClass" xsi:type="string">billing-address</item> - <item name="title" translate="true" xsi:type="string">Default Billing Address</item> - <item name="contentClass" xsi:type="string">customer-default-billing-address-content</item> - <item name="notExistsMessage" xsi:type="string" translate="true">The customer does not have default billing address</item> - <item name="tracks" xsi:type="array"> - <item name="address" xsi:type="boolean">true</item> - </item> - </item> - </argument> - <settings> - <imports> - <link name="address">${ $.provider}:data.default_billing_address</link> - </imports> - </settings> - </component> - - <button name="edit_billing_address" component="Magento_Customer/js/address/default-address"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="buttonClasses" xsi:type="string">edit-default-billing-address-button</item> - <item name="actions" xsi:type="array"> - <item name="0" xsi:type="array"> - <item name="targetName" xsi:type="string">${ $.parentName}.customer_address_update_modal.update_customer_address_form_loader</item> - <item name="actionName" xsi:type="string">destroyInserted</item> - </item> - <item name="1" xsi:type="array"> - <item name="targetName" xsi:type="string">${ $.parentName}.customer_address_update_modal</item> - <item name="actionName" xsi:type="string">openModal</item> - </item> - <item name="2" xsi:type="array"> - <item name="targetName" xsi:type="string">${ $.parentName}.customer_address_update_modal.update_customer_address_form_loader</item> - <item name="actionName" xsi:type="string">render</item> + <component name="customer_default_billing_address_wrapper" template="Magento_Customer/default-address-wrapper"> + <component name="customer_default_billing_address_content" template="Magento_Customer/default-address"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="defaultAddressClass" xsi:type="string">billing-address</item> + <item name="title" translate="true" xsi:type="string">Default Billing Address</item> + <item name="contentClass" xsi:type="string">customer-default-billing-address-content</item> + <item name="notExistsMessage" xsi:type="string" translate="true">The customer does not have default billing address</item> + <item name="tracks" xsi:type="array"> + <item name="address" xsi:type="boolean">true</item> </item> </item> - </item> - </argument> - <settings> - <componentType>button</componentType> - <title translate="true">Edit - true - - ${ $.provider}:data.default_billing_address.entity_id - ${ $.provider}:data.default_billing_address - - - - - - - - shipping-address - Default Shipping Address - customer-default-shipping-address-content - The customer does not have default shipping address - - true + + + + ${ $.provider}:data.default_billing_address + + + + - - + + + button + Edit + true + + ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address + + + + + + + button + Edit + true + + ${ $.provider}:data.default_billing_address.entity_id + ${ $.provider}:data.default_billing_address + + + + @@ -380,37 +380,37 @@ ${ $.provider}:data.default_shipping_address - - + + + button + Edit + true + + ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address + + + + - + + + + button + Edit + true + + ${ $.provider}:data.default_billing_address.entity_id + ${ $.provider}:data.default_billing_address + + + @@ -378,39 +378,39 @@ ${ $.provider}:data.default_shipping_address - + efas - - + + + + button + Edit + true + + ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address + + +