diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 21c12bf0a8b1a..75ec58ff90876 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1317,7 +1317,7 @@ public function saveProductEntity(array $entityRowsIn, array $entityRowsUp) $select = $this->_connection->select()->from( $entityTable, - $this->getNewSkuFieldsForSelect() + array_merge($this->getNewSkuFieldsForSelect(), $this->getOldSkuFieldsForSelect()) )->where( 'sku IN (?)', array_keys($entityRowsIn) @@ -1330,10 +1330,45 @@ public function saveProductEntity(array $entityRowsIn, array $entityRowsUp) $this->skuProcessor->setNewSkuData($sku, $key, $value); } } + + $this->updateOldSku($newProducts); } + return $this; } + /** + * Return additional data, needed to select. + * @return array + */ + private function getOldSkuFieldsForSelect() + { + return ['type_id', 'attribute_set_id']; + } + + /** + * Adds newly created products to _oldSku + * @param array $newProducts + * @return void + */ + private function updateOldSku(array $newProducts) + { + $oldSkus = []; + foreach ($newProducts as $info) { + $typeId = $info['type_id']; + $sku = $info['sku']; + $oldSkus[$sku] = [ + 'type_id' => $typeId, + 'attr_set_id' => $info['attribute_set_id'], + $this->getProductIdentifierField() => $info[$this->getProductIdentifierField()], + 'supported_type' => isset($this->_productTypeModels[$typeId]), + $this->getProductEntityLinkField() => $info[$this->getProductEntityLinkField()], + ]; + } + + $this->_oldSku = array_replace($this->_oldSku, $oldSkus); + } + /** * Get new SKU fields for select * @@ -1718,6 +1753,7 @@ protected function _saveProducts() ['adapter' => $this, 'bunch' => $bunch] ); } + return $this; } @@ -2452,6 +2488,7 @@ protected function _saveValidatedBunches() { $source = $this->_getSource(); $source->rewind(); + while ($source->valid()) { try { $rowData = $source->current(); @@ -2465,6 +2502,7 @@ protected function _saveValidatedBunches() $rowData = $this->_customFieldsMapping($rowData); $this->validateRow($rowData, $source->key()); + $source->next(); } $this->checkUrlKeyDuplicates(); diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php b/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php new file mode 100644 index 0000000000000..16a296a355454 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php @@ -0,0 +1,60 @@ +configurableOptionsProvider = $configurableOptionsProvider; + parent::__construct($context, $saleableItem, $price, $rendererPool, $data); + } + + /** + * Define if the special price should be shown + * + * @return bool + */ + public function hasSpecialPrice() + { + $product = $this->getSaleableItem(); + foreach ($this->configurableOptionsProvider->getProducts($product) as $subProduct) { + $regularPrice = $subProduct->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE)->getValue(); + $finalPrice = $subProduct->getPriceInfo()->getPrice(FinalPrice::PRICE_CODE)->getValue(); + if ($finalPrice < $regularPrice) { + return true; + } + } + return false; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php new file mode 100644 index 0000000000000..4dbcfed531525 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php @@ -0,0 +1,137 @@ +context = $this->getMockBuilder(\Magento\Framework\View\Element\Template\Context::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->saleableItem = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->price = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class) + ->getMockForAbstractClass(); + + $this->rendererPool = $this->getMockBuilder(\Magento\Framework\Pricing\Render\RendererPool::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configurableOptionsProvider = $this->getMockBuilder(ConfigurableOptionsProviderInterface::class) + ->getMockForAbstractClass(); + + $this->model = new FinalPriceBox( + $this->context, + $this->saleableItem, + $this->price, + $this->rendererPool, + $this->configurableOptionsProvider + ); + } + + /** + * @param float $regularPrice + * @param float $finalPrice + * @param bool $expected + * @dataProvider hasSpecialPriceDataProvider + */ + public function testHasSpecialPrice( + $regularPrice, + $finalPrice, + $expected + ) { + $priceMockOne = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class) + ->getMockForAbstractClass(); + + $priceMockOne->expects($this->once()) + ->method('getValue') + ->willReturn($regularPrice); + + $priceMockTwo = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class) + ->getMockForAbstractClass(); + + $priceMockTwo->expects($this->once()) + ->method('getValue') + ->willReturn($finalPrice); + + $priceInfoMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class) + ->disableOriginalConstructor() + ->getMock(); + + $priceInfoMock->expects($this->exactly(2)) + ->method('getPrice') + ->willReturnMap([ + [RegularPrice::PRICE_CODE, $priceMockOne], + [FinalPrice::PRICE_CODE, $priceMockTwo], + ]); + + $productMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->setMethods(['getPriceInfo']) + ->getMockForAbstractClass(); + + $productMock->expects($this->exactly(2)) + ->method('getPriceInfo') + ->willReturn($priceInfoMock); + + $this->configurableOptionsProvider->expects($this->once()) + ->method('getProducts') + ->with($this->saleableItem) + ->willReturn([$productMock]); + + $this->assertEquals($expected, $this->model->hasSpecialPrice()); + } + + /** + * @return array + */ + public function hasSpecialPriceDataProvider() + { + return [ + [10., 20., false], + [10., 10., false], + [20., 10., true], + ]; + } +} diff --git a/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml new file mode 100644 index 0000000000000..47fe31681b5bf --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml @@ -0,0 +1,21 @@ + + + + + + + + + Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox + Magento_ConfigurableProduct::product/price/final_price.phtml + + + + + + diff --git a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml new file mode 100644 index 0000000000000..5943b1ea2af5b --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml @@ -0,0 +1,60 @@ + + +getPriceType('regular_price'); + +/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */ +$finalPriceModel = $block->getPriceType('final_price'); +$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; +$schema = ($block->getZone() == 'item_view') ? true : false; +?> +hasSpecialPrice()): ?> + + renderAmount($finalPriceModel->getAmount(), [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ]); ?> + + + renderAmount($priceModel->getAmount(), [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ]); ?> + + + renderAmount($finalPriceModel->getAmount(), [ + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ]); ?> + + +showMinimalPrice()): ?> + getUseLinkForAsLowAs()):?> + + renderAmountMinimal(); ?> + + + + renderAmountMinimal(); ?> + + + diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js index bd0314aacf711..7bea20e786201 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js @@ -28,6 +28,7 @@ define([ '<% } %>', mediaGallerySelector: '[data-gallery-role=gallery-placeholder]', mediaGalleryInitial: null, + slyOldPriceSelector: '.sly-old-price', onlyMainImg: false }, @@ -248,6 +249,7 @@ define([ this._resetChildren(element); } this._reloadPrice(); + this._displayRegularPriceBlock(this.simpleProduct); this._changeProductImage(); }, @@ -444,7 +446,7 @@ define([ }, /** - * Returns pracies for configured products + * Returns prices for configured products * * @param {*} config - Products configuration * @returns {*} @@ -487,6 +489,23 @@ define([ undefined : _.first(config.allowedProducts); + }, + + /** + * Show or hide regular price block + * + * @param {*} optionId + * @private + */ + _displayRegularPriceBlock: function (optionId) { + if (typeof optionId != 'undefined' + && this.options.spConfig.optionPrices[optionId].oldPrice.amount + != this.options.spConfig.optionPrices[optionId].finalPrice.amount + ) { + $(this.options.slyOldPriceSelector).show(); + } else { + $(this.options.slyOldPriceSelector).hide(); + } } }); diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 41ffb74184bad..fdb9c3f317a4c 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -256,6 +256,10 @@ Send Welcome Email From number select + customer + + ${ $.provider }:data.customer.store_id + diff --git a/app/code/Magento/Wishlist/Helper/Data.php b/app/code/Magento/Wishlist/Helper/Data.php index d64d1a185f0a2..736786e6e30b3 100644 --- a/app/code/Magento/Wishlist/Helper/Data.php +++ b/app/code/Magento/Wishlist/Helper/Data.php @@ -446,7 +446,13 @@ public function getSharedAddAllToCartUrl() */ protected function _getCartUrlParameters($item) { - return ['item' => is_string($item) ? $item : $item->getWishlistItemId()]; + $params = [ + 'item' => is_string($item) ? $item : $item->getWishlistItemId(), + ]; + if ($item instanceof \Magento\Wishlist\Model\Item) { + $params['qty'] = $item->getQty(); + } + return $params; } /** diff --git a/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php b/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php index 46054445620ac..ec6e959a3d4ca 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php @@ -124,6 +124,7 @@ protected function setUp() ->setMethods([ 'getProduct', 'getWishlistItemId', + 'getQty', ]) ->getMock(); @@ -217,6 +218,7 @@ public function testGetAddToCartParams() $url = 'result url'; $storeId = 1; $wishlistItemId = 1; + $wishlistItemQty = 1; $this->wishlistItem->expects($this->once()) ->method('getProduct') @@ -224,6 +226,9 @@ public function testGetAddToCartParams() $this->wishlistItem->expects($this->once()) ->method('getWishlistItemId') ->willReturn($wishlistItemId); + $this->wishlistItem->expects($this->once()) + ->method('getQty') + ->willReturn($wishlistItemQty); $this->product->expects($this->once()) ->method('isVisibleInSiteVisibility') @@ -243,9 +248,13 @@ public function testGetAddToCartParams() ->with('wishlist/index/cart') ->willReturn($url); + $expected = [ + 'item' => $wishlistItemId, + 'qty' => $wishlistItemQty, + ]; $this->postDataHelper->expects($this->once()) ->method('getPostData') - ->with($url, ['item' => $wishlistItemId]) + ->with($url, $expected) ->willReturn($url); $this->assertEquals($url, $this->model->getAddToCartParams($this->wishlistItem)); @@ -256,6 +265,7 @@ public function testGetAddToCartParamsWithReferer() $url = 'result url'; $storeId = 1; $wishlistItemId = 1; + $wishlistItemQty = 1; $referer = 'referer'; $refererEncoded = 'referer_encoded'; @@ -265,6 +275,9 @@ public function testGetAddToCartParamsWithReferer() $this->wishlistItem->expects($this->once()) ->method('getWishlistItemId') ->willReturn($wishlistItemId); + $this->wishlistItem->expects($this->once()) + ->method('getQty') + ->willReturn($wishlistItemQty); $this->product->expects($this->once()) ->method('isVisibleInSiteVisibility') @@ -288,9 +301,14 @@ public function testGetAddToCartParamsWithReferer() ->with('wishlist/index/cart') ->willReturn($url); + $expected = [ + 'item' => $wishlistItemId, + ActionInterface::PARAM_NAME_URL_ENCODED => $refererEncoded, + 'qty' => $wishlistItemQty, + ]; $this->postDataHelper->expects($this->once()) ->method('getPostData') - ->with($url, ['item' => $wishlistItemId, ActionInterface::PARAM_NAME_URL_ENCODED => $refererEncoded]) + ->with($url, $expected) ->willReturn($url); $this->assertEquals($url, $this->model->getAddToCartParams($this->wishlistItem, true)); @@ -363,6 +381,7 @@ public function testGetSharedAddToCartUrl() $url = 'result url'; $storeId = 1; $wishlistItemId = 1; + $wishlistItemQty = 1; $this->wishlistItem->expects($this->once()) ->method('getProduct') @@ -370,6 +389,9 @@ public function testGetSharedAddToCartUrl() $this->wishlistItem->expects($this->once()) ->method('getWishlistItemId') ->willReturn($wishlistItemId); + $this->wishlistItem->expects($this->once()) + ->method('getQty') + ->willReturn($wishlistItemQty); $this->product->expects($this->once()) ->method('isVisibleInSiteVisibility') @@ -383,9 +405,13 @@ public function testGetSharedAddToCartUrl() ->with('wishlist/shared/cart') ->willReturn($url); + $exptected = [ + 'item' => $wishlistItemId, + 'qty' => $wishlistItemQty, + ]; $this->postDataHelper->expects($this->once()) ->method('getPostData') - ->with($url, ['item' => $wishlistItemId]) + ->with($url, $exptected) ->willReturn($url); $this->assertEquals($url, $this->model->getSharedAddToCartUrl($this->wishlistItem)); diff --git a/app/code/Magento/Wishlist/view/frontend/web/wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/wishlist.js index a4fdc178c704f..0d6e510e5f5e9 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/wishlist.js @@ -47,6 +47,7 @@ define([ event.preventDefault(); $.mage.dataPost().postData($(event.currentTarget).data('post-remove')); }, this)) + .on('click', this.options.addToCartSelector, $.proxy(this._beforeAddToCart, this)) .on('click', this.options.addAllToCartSelector, $.proxy(this._addAllWItemsToCart, this)) .on('focusin focusout', this.options.commentInputType, $.proxy(this._focusComment, this)); } @@ -59,6 +60,27 @@ define([ }); }, + /** + * Process data before add to cart + * + * - update item's qty value. + * + * @param {Event} event + * @private + */ + _beforeAddToCart: function(event) { + var elem = $(event.currentTarget), + itemId = elem.data(this.options.dataAttribute), + qtyName = $.validator.format(this.options.nameFormat, itemId), + qtyValue = elem.parents().find('[name="' + qtyName + '"]').val(), + params = elem.data('post'); + + if (params) { + params.data = $.extend({}, params.data, {'qty': qtyValue}); + elem.data('post', params); + } + }, + /** * Add wish list items to cart. * @private diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml index 593ab70e100ff..42f490d76191a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml @@ -134,11 +134,11 @@ xpath - text + datepicker input[name='custom_design_from'] - text + datepicker input[name='custom_design_to'] diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php index e660b0ea05fab..2ccb804b073f9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php @@ -413,12 +413,12 @@ protected function prepareWebsites() { if (!empty($this->fields['product']['website_ids'])) { foreach ($this->fixture->getDataFieldConfig('website_ids')['source']->getWebsites() as $key => $website) { - $this->fields['product']['website_ids'][$key] = $website->getWebsiteId(); + $this->fields['product']['extension_attributes']['website_ids'][$key] = $website->getWebsiteId(); } } else { $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager() ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']); - $this->fields['product']['website_ids'][] = $website->getWebsiteId(); + $this->fields['product']['extension_attributes']['website_ids'][] = $website->getWebsiteId(); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php index 4ec372ab7163b..4c3d344832f85 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php @@ -64,13 +64,6 @@ class Webapi extends AbstractWebApi implements CatalogProductSimpleInterface 'custom_attributes' ]; - /** - * Website Ids for current Product. - * - * @var array - */ - private $websiteIds = []; - /** * @constructor * @param DataInterface $configuration @@ -102,8 +95,6 @@ public function persist(FixtureInterface $fixture = null) $this->prepareData(); $this->convertData(); - //TODO: Change create and assign product to website flow using 1 request after MAGETWO-52812 delivery. - /** @var CatalogProductSimple $fixture */ $url = $_ENV['app_frontend_url'] . 'rest/all/V1/products'; $this->webapiTransport->write($url, $this->fields, CurlInterface::POST); @@ -116,110 +107,9 @@ public function persist(FixtureInterface $fixture = null) throw new \Exception("Product creation by webapi handler was not successful! Response: {$encodedResponse}"); } - $this->assignToWebsites($response); - return $this->parseResponse($response); } - /** - * Assign appropriate Websites to Product and unset all other. - * - * @param array $product - * @return void - */ - private function assignToWebsites($product) - { - $this->setWebsites($product); - $this->unsetWebsites($product); - } - - /** - * Get all Websites. - * - * @return array - * @throws \Exception - */ - private function getAllWebsites() - { - $url = $_ENV['app_frontend_url'] . 'rest/V1/store/websites'; - $this->webapiTransport->write($url, [], CurlInterface::GET); - $encodedResponse = $this->webapiTransport->read(); - $response = json_decode($encodedResponse, true); - $this->webapiTransport->close(); - - if (!isset($response[0]['id'])) { - $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); - throw new \Exception( - "Attempt to get all Websites by webapi handler was not successful! Response: {$encodedResponse}" - ); - } - - return $response; - } - - /** - * Set appropriate Websites to Product. - * - * @param array $product - * @return void - * @throws \Exception - */ - private function setWebsites($product) - { - foreach ($this->websiteIds as $id) { - $url = $_ENV['app_frontend_url'] . 'rest/V1/products/' . $product['sku'] . '/websites'; - $productWebsiteLink = ['productWebsiteLink' => ['website_id' => $id, 'sku' => $product['sku']]]; - $this->webapiTransport->write($url, $productWebsiteLink, CurlInterface::POST); - $encodedResponse = $this->webapiTransport->read(); - $response = json_decode($encodedResponse, true); - $this->webapiTransport->close(); - - if ($response !== true) { - $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); - throw new \Exception( - "Product addition to Website by webapi handler was not successful! Response: {$encodedResponse}" - ); - } - } - } - - /** - * Unset all Websites from Product except appropriate. - * - * @param array $product - * @return void - * @throws \Exception - */ - private function unsetWebsites($product) - { - $allWebsites = $this->getAllWebsites(); - $websiteIds = []; - - foreach ($allWebsites as $website) { - if ($website['code'] == 'admin') { - continue; - } - $websiteIds[] = $website['id']; - } - - $websiteIds = array_diff($websiteIds, $this->websiteIds); - - foreach ($websiteIds as $id) { - $url = $_ENV['app_frontend_url'] . 'rest/V1/products/' . $product['sku'] . '/websites/' . $id; - $this->webapiTransport->write($url, [], CurlInterface::DELETE); - $encodedResponse = $this->webapiTransport->read(); - $response = json_decode($encodedResponse, true); - $this->webapiTransport->close(); - - if ($response !== true) { - $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); - throw new \Exception( - "Product deduction from Website by webapi handler was not successful! Response: {$encodedResponse}" - ); - } - } - } - /** * Prepare data for creating product request. * @@ -244,7 +134,6 @@ protected function prepareData() protected function convertData() { $fields = []; - $this->websiteIds = $this->fields['product']['website_ids']; unset($this->fields['product']['website_ids']); unset($this->fields['product']['checkout_data']); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml index 23c13fb1206df..ecd68593b08cc 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml @@ -1215,7 +1215,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-%isolation% diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php index 402aa6ba0d318..bf5d5944aa3da 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php @@ -61,6 +61,24 @@ public function prepareData(FixtureInterface $fixture) return $data; } + /** + * Preparation of websites data. + * + * @return void + */ + protected function prepareWebsites() + { + if (!empty($this->fields['product']['website_ids'])) { + foreach ($this->fixture->getDataFieldConfig('website_ids')['source']->getWebsites() as $key => $website) { + $this->fields['product']['website_ids'][$key] = $website->getWebsiteId(); + } + } else { + $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager() + ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']); + $this->fields['product']['website_ids'][] = $website->getWebsiteId(); + } + } + /** * Preparation of attribute set data. * diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml index 664f96cd4b42f..bb56a9edaf9a1 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml @@ -24,6 +24,9 @@ select + + datepicker + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml index 6997cca28fac0..248b26561af3a 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml @@ -27,7 +27,7 @@ Doe%isolation% S JohnDoe%isolation%@example.com - Mar 16, 2004 + 03/16/2004 Male diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml index ac63dcaf2805e..c2132672d900a 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml @@ -16,7 +16,7 @@ Doe%isolation% _Suffix%isolation% JohnDoe%isolation%@example.com - Aug 1, 1986 + 08/01/1986 123456789001 Male @@ -52,7 +52,7 @@ Doe%isolation% _JaneSuffix%isolation% Jane%isolation%@example.com - Dec 1, 2000 + 01/12/2000 987654321 Female Prefix%isolation%_ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php new file mode 100644 index 0000000000000..9f7cc54fe88ca --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php @@ -0,0 +1,29 @@ + [ + 'selector' => 'input[name="title"]', + ], + 'sku' => [ + 'selector' => 'input[name="sku"]', + ], + ]; +} diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php index 3ba4369fb0fcc..afadc1b0858ae 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php @@ -34,7 +34,7 @@ class RatingElement extends SimpleElement * * @var string */ - protected $ratingByNumber = './/*[@id="rating_detail"]//*[contains(@class,"field-rating")][%d]'; + protected $ratingByNumber = './/*[contains(@class,"field-rating")][%d]'; /** * Set rating value diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php index 37ea3df90a89f..5b45f54600ceb 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php @@ -23,12 +23,12 @@ class Reviews extends Section /** * Returns product reviews grid. * - * @return \Magento\Review\Test\Block\Adminhtml\Product\Grid + * @return \Magento\Review\Test\Block\Adminhtml\Edit\Product\Grid */ public function getReviewsGrid() { return $this->blockFactory->create( - \Magento\Review\Test\Block\Adminhtml\Product\Grid::class, + \Magento\Review\Test\Block\Adminhtml\Edit\Product\Grid::class, ['element' => $this->_rootElement->find($this->reviews)] ); } diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php index 55060e7a85db9..e1aa3b9d5a9a5 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php @@ -6,13 +6,20 @@ namespace Magento\Review\Test\Block\Adminhtml\Product; -use Magento\Ui\Test\Block\Adminhtml\DataGrid; +use Magento\Backend\Test\Block\Widget\Grid as AbstractGrid; /** * Review catalog product grid. */ -class Grid extends DataGrid +class Grid extends AbstractGrid { + /** + * First row selector + * + * @var string + */ + protected $firstRowSelector = './/tbody/tr[1]'; + /** * Grid filter selectors * diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml index 1832618a7da64..348cd3429149a 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml @@ -20,7 +20,7 @@ textarea - #detailed_rating + #rating_detail Magento\Review\Test\Block\Adminhtml\Edit\RatingElement diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php index 6bb20785adf91..91ab33e5ca321 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php @@ -37,14 +37,14 @@ class ReviewForm extends AbstractForm * * @var string */ - protected $rating = './/*[@id="%s_rating_label"]/span'; + protected $rating = './/*[@id="%s_rating_label"]'; /** * Selector for label of rating vote. * * @var string */ - protected $ratingVoteLabel = './div[contains(@class,"vote")]/label[contains(@id,"_%d_label")]'; + protected $ratingVoteLabel = './following-sibling::div[contains(@class,"vote")]/label[contains(@id,"_%d_label")]'; /** * Submit review form. diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php index aeeff3480e4a6..9130c5285848e 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php @@ -109,13 +109,14 @@ public function test(Review $review) { // Precondition: $product = $review->getDataFieldConfig('entity_id')['source']->getEntity(); - $filter = ['id' => $product->getId()]; + $filter = ['sku' => $product->getSku()]; $this->review = $review; // Steps: $this->reviewIndex->open(); $this->reviewIndex->getReviewActions()->addNew(); - $this->reviewEdit->getProductGrid()->searchAndOpen($filter); + $this->reviewEdit->getProductGrid()->search($filter); + $this->reviewEdit->getProductGrid()->openFirstRow(); $this->reviewEdit->getReviewForm()->fill($this->review); $this->reviewEdit->getPageActions()->save(); diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php index eae09d72a47b9..3fc6f044f8852 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php @@ -135,7 +135,7 @@ class DataGrid extends Grid * * @var string */ - protected $sortLink = "//th[contains(@class, '%s')]/span[contains(text(), '%s')]"; + protected $sortLink = './/div[@data-role="grid-wrapper"]//th[contains(@class, "%s")]/span[contains(text(), "%s")]'; /** * Current page input. diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index a1762a065ba88..db5511bf9d8ff 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -14,6 +14,7 @@ */ namespace Magento\CatalogImportExport\Model\Import; +use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Category; use Magento\Framework\App\Bootstrap; @@ -557,7 +558,7 @@ protected function getOptionValues(\Magento\Catalog\Model\Product\Option $option /** * @magentoDataIsolation enabled * @magentoDataFixture mediaImportImageFixture - * + * @magentoAppIsolation enabled * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testSaveMediaImage() @@ -732,6 +733,7 @@ public function testInvalidSkuLink() /** * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php * @magentoAppIsolation enabled + * @magentoDbIsolation enabled */ public function testValidateInvalidMultiselectValues() { @@ -1268,4 +1270,62 @@ public function testProductWithUseConfigSettings() $this->assertEquals($manageStockUseConfig, $stockItem->getUseConfigManageStock()); } } + + /** + * @magentoDataFixture Magento/Store/_files/website.php + * @magentoDataFixture Magento/Store/_files/core_fixturestore.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testProductWithMultipleStoresInDifferentBunches() + { + $products = [ + 'simple1', + 'simple2', + 'simple3' + ]; + + $importExportData = $this->getMockBuilder(\Magento\ImportExport\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + $importExportData->expects($this->atLeastOnce()) + ->method('getBunchSize') + ->willReturn(1); + $this->_model = $this->objectManager->create( + \Magento\CatalogImportExport\Model\Import\Product::class, + ['importExportData' => $importExportData] + ); + + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/products_to_import_with_multiple_store.csv', + 'directory' => $directory + ] + ); + $errors = $this->_model->setParameters( + ['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'entity' => 'catalog_product'] + )->setSource( + $source + )->validateData(); + + $this->assertTrue($errors->getErrorsCount() == 0); + + $this->_model->importData(); + $productCollection = $this->objectManager + ->create(\Magento\Catalog\Model\ResourceModel\Product\Collection::class); + $this->assertCount(3, $productCollection->getItems()); + $actualProductSkus = array_map( + function(ProductInterface $item) { + return $item->getSku(); + }, + $productCollection->getItems() + ); + $this->assertEquals( + $products, + array_values($actualProductSkus) + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_multiple_store.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_multiple_store.csv new file mode 100644 index 0000000000000..a4ad5adb7b0f4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_multiple_store.csv @@ -0,0 +1,6 @@ +sku,product_type,store_view_code,name,price,attribute_set_code,categories +simple1,simple,fixturestore,"simple 1",25,Default,"Default Category/Category 1" +simple1,simple,,"simple 1",25,Default,"Default Category/Category 1" +simple2,simple,fixturestore,"simple 2",34,Default,"Default Category/Category 1" +simple2,simple,,"simple 2",34,Default,"Default Category/Category 1" +simple3,simple,,"simple 3",58,Default,"Default Category/Category 1" diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php index 16ca335beea7b..bb899fa6af598 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php @@ -12,7 +12,7 @@ */ class ValidatorTest extends \PHPUnit_Framework_TestCase { - const TEMPLATE_CODE = 'fixture'; + const TEMPLATE_CODE = 'email_exception_fixture'; /** * @var \Magento\Theme\Model\Design\Config\Validator @@ -44,7 +44,9 @@ protected function setUp() $this->templateModel = $objectManager->create(\Magento\Email\Model\Template::class); $this->templateModel->load(self::TEMPLATE_CODE, 'template_code'); - + $this->templateFactoryMock->expects($this->once()) + ->method("create") + ->willReturn($this->templateModel); $this->model = $objectManager->create( \Magento\Theme\Model\Design\Config\Validator::class, [ 'templateFactory' => $this->templateFactoryMock ] @@ -58,9 +60,9 @@ protected function setUp() */ public function testValidateHasRecursiveReference() { - $this->templateFactoryMock->expects($this->once()) - ->method("create") - ->willReturn($this->templateModel); + if (!$this->templateModel->getId()) { + $this->fail('Cannot load Template model'); + } $fieldConfig = [ 'path' => 'design/email/header_template', @@ -90,7 +92,7 @@ public function testValidateHasRecursiveReference() ->willReturn([$designElementMock]); $designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig); $designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']); - $designElementMock->expects($this->once())->method('getValue')->willReturn(1); + $designElementMock->expects($this->once())->method('getValue')->willReturn($this->templateModel->getId()); $this->model->validate($designConfigMock); } @@ -132,7 +134,7 @@ public function testValidateNoRecursiveReference() ->willReturn([$designElementMock]); $designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig); $designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']); - $designElementMock->expects($this->once())->method('getValue')->willReturn(1); + $designElementMock->expects($this->once())->method('getValue')->willReturn($this->templateModel->getId()); $this->model->validate($designConfigMock); }