diff --git a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js index 1a76acf17475670674c064c8384d628b87d924a7..607ac6e03a75a8beeb644c84a11400eee09012d9 100644 --- a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js +++ b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js @@ -295,6 +295,10 @@ define([ case 'hidden': optionHash = 'bundle-option-' + optionName + '##' + optionValue; optionQty = optionConfig[optionValue].qty || 0; + canQtyCustomize = optionConfig[optionValue].customQty === '1'; + qtyField = element.data('qtyField'); + qtyField.data('option', element); + toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize); tempChanges = utils.deepClone(optionConfig[optionValue].prices); tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig); tempChanges = applyQty(tempChanges, optionQty); diff --git a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php index d9702c5073fb653c132c89d761e9ddf14faa34c1..f1bb89d4424f7f4436abea0c137a0457a0ad13c8 100644 --- a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php +++ b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php @@ -124,7 +124,7 @@ class AbstractProduct extends \Magento\Framework\View\Element\Template */ public function getAddToCartUrl($product, $additional = []) { - if ($product->getTypeInstance()->hasRequiredOptions($product)) { + if (!$product->getTypeInstance()->isPossibleBuyFromList($product)) { if (!isset($additional['_escape'])) { $additional['_escape'] = true; } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php index 4375092591d194962b108e2ba0351b1a03fa7e5c..40516e55e930c4021699dad26b43a4e83fe26a80 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php @@ -281,7 +281,7 @@ class FlatTableBuilder if (!empty($columnValueNames)) { $select->joinLeft( $temporaryValueTableName, - sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryTableName), + sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryValueTableName), $columnValueNames ); $allColumns = array_merge($allColumns, $columnValueNames); diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php index 6de6ea6c6c6bca8029aee2be5749d555690d48c8..11b8d03fc7ee5cc23dd627e65ad9651a5b243b7d 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php +++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php @@ -1092,4 +1092,15 @@ abstract class AbstractType { return []; } + + /** + * Check if product can be potentially buyed from the category page or some other list + * + * @param \Magento\Catalog\Model\Product $product + * @return bool + */ + public function isPossibleBuyFromList($product) + { + return !$this->hasRequiredOptions($product); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php index f420f140b35820e3cbcebf986ed305217523aab2..39e3263722a7c3f84fce9f6ce3e5b8ee2f2899d6 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php @@ -154,9 +154,9 @@ class ListProductTest extends \PHPUnit_Framework_TestCase ]; $this->typeInstanceMock->expects($this->once()) - ->method('hasRequiredOptions') + ->method('isPossibleBuyFromList') ->with($this->equalTo($this->productMock)) - ->will($this->returnValue(false)); + ->will($this->returnValue(true)); $this->cartHelperMock->expects($this->any()) ->method('getAddUrl') ->with($this->equalTo($this->productMock), $this->equalTo([])) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php index 7e5a8305467e8e979a9ccc79d39d7ffdb70bb339..d90261f068f5023d8987bab6d64585032385c8ee 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php @@ -107,44 +107,42 @@ class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase public function testBuild() { - list($storeId, $changedIds, $valueFieldSuffix, $tableDropSuffix, $fillTmpTables) = [1, [], '', '', true]; + $storeId = 1; + $changedIds = []; + $valueFieldSuffix = '_value'; + $tableDropSuffix = ''; + $fillTmpTables = true; $tableName = 'catalog_product_entity'; $attributeTable = 'catalog_product_entity_int'; $temporaryTableName = 'catalog_product_entity_int_tmp_indexer'; - $temporaryValueTableName = 'catalog_product_entity_int_tmp_indexer'; + $temporaryValueTableName = 'catalog_product_entity_int_tmp_indexer_value'; $linkField = 'entity_id'; $statusId = 22; + $eavCustomField = 'space_weight'; + $eavCustomValueField = $eavCustomField . $valueFieldSuffix; $this->flatIndexerMock->expects($this->once())->method('getAttributes')->willReturn([]); $this->flatIndexerMock->expects($this->exactly(3))->method('getFlatColumns') - ->willReturnOnConsecutiveCalls( - [], - [$linkField => []], - [$linkField => []] - ); + ->willReturnOnConsecutiveCalls([], [$eavCustomValueField => []], [$eavCustomValueField => []]); $this->flatIndexerMock->expects($this->once())->method('getFlatIndexes')->willReturn([]); $statusAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute::class) ->disableOriginalConstructor() ->getMock(); + $eavCustomAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); $this->flatIndexerMock->expects($this->once())->method('getTablesStructure') ->willReturn( [ - 'catalog_product_entity' => [ - $linkField => $statusAttributeMock - ], + 'catalog_product_entity' => [$linkField => $statusAttributeMock], 'catalog_product_entity_int' => [ - $linkField => $statusAttributeMock + $linkField => $statusAttributeMock, + $eavCustomField => $eavCustomAttributeMock ] ] ); $this->flatIndexerMock->expects($this->atLeastOnce())->method('getTable') - ->withConsecutive( - [$tableName], - ['catalog_product_website'] - ) - ->willReturnOnConsecutiveCalls( - $tableName, - 'catalog_product_website' - ); + ->withConsecutive([$tableName], ['catalog_product_website']) + ->willReturnOnConsecutiveCalls($tableName, 'catalog_product_website'); $this->flatIndexerMock->expects($this->once())->method('getAttribute') ->with('status') ->willReturn($statusAttributeMock); @@ -155,6 +153,9 @@ class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase $statusAttributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn( $backendMock ); + $eavCustomAttributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn( + $backendMock + ); $statusAttributeMock->expects($this->atLeastOnce())->method('getId')->willReturn($statusId); $tableMock = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Table::class) ->disableOriginalConstructor() @@ -185,12 +186,12 @@ class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase [ $temporaryTableName, "e.{$linkField} = {$temporaryTableName}.{$linkField}", - [$linkField] + [$linkField, $eavCustomField] ], [ $temporaryValueTableName, - "e.{$linkField} = " . $temporaryValueTableName . ".{$linkField}", - [$linkField] + "e.{$linkField} = {$temporaryValueTableName}.{$linkField}", + [$eavCustomValueField] ] )->willReturnSelf(); $this->metadataPoolMock->expects($this->atLeastOnce())->method('getMetadata')->with(ProductInterface::class) diff --git a/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js b/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js index 45c9f73e051c788c55f24d2f95f1e286c7d6bd02..7db4f5d745626c0da12d9a4032bc5466c57f282b 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js @@ -84,6 +84,17 @@ define([ } if (res.backUrl) { + var eventData = { + 'form': form, + 'redirectParameters': [] + } + // trigger global event, so other modules will be able add parameters to redirect url + $('body').trigger('catalogCategoryAddToCartRedirect', eventData); + if (eventData.redirectParameters.length > 0) { + var parameters = res.backUrl.split('#'); + parameters.push(eventData.redirectParameters.join('&')); + res.backUrl = parameters.join('#'); + } window.location = res.backUrl; return; } diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml index a1476c2c3f8b161568a042725d6b04c37aeb1be9..d9db59b7a17663b48b2ba2df7677d4147cba11b5 100644 --- a/app/code/Magento/CatalogInventory/etc/events.xml +++ b/app/code/Magento/CatalogInventory/etc/events.xml @@ -33,9 +33,6 @@ <event name="sales_order_item_cancel"> <observer name="inventory" instance="Magento\CatalogInventory\Observer\CancelOrderItemObserver"/> </event> - <event name="sales_order_creditmemo_save_after"> - <observer name="inventory" instance="Magento\CatalogInventory\Observer\RefundOrderInventoryObserver"/> - </event> <event name="catalog_product_save_after"> <observer name="inventory" instance="Magento\CatalogInventory\Observer\SaveInventoryDataObserver"/> </event> diff --git a/app/code/Magento/Checkout/Controller/Cart/CouponPost.php b/app/code/Magento/Checkout/Controller/Cart/CouponPost.php index 2b3f65728068bee22560f06943f88eea69e36d79..0498b22d550e7f8c78cc2af53819a31aebeb3d47 100644 --- a/app/code/Magento/Checkout/Controller/Cart/CouponPost.php +++ b/app/code/Magento/Checkout/Controller/Cart/CouponPost.php @@ -90,26 +90,17 @@ class CouponPost extends \Magento\Checkout\Controller\Cart if ($codeLength) { $escaper = $this->_objectManager->get(\Magento\Framework\Escaper::class); + $coupon = $this->couponFactory->create(); + $coupon->load($couponCode, 'code'); if (!$itemsCount) { - if ($isCodeLengthValid) { - $coupon = $this->couponFactory->create(); - $coupon->load($couponCode, 'code'); - if ($coupon->getId()) { - $this->_checkoutSession->getQuote()->setCouponCode($couponCode)->save(); - $this->messageManager->addSuccess( - __( - 'You used coupon code "%1".', - $escaper->escapeHtml($couponCode) - ) - ); - } else { - $this->messageManager->addError( - __( - 'The coupon code "%1" is not valid.', - $escaper->escapeHtml($couponCode) - ) - ); - } + if ($isCodeLengthValid && $coupon->getId()) { + $this->_checkoutSession->getQuote()->setCouponCode($couponCode)->save(); + $this->messageManager->addSuccess( + __( + 'You used coupon code "%1".', + $escaper->escapeHtml($couponCode) + ) + ); } else { $this->messageManager->addError( __( @@ -119,7 +110,7 @@ class CouponPost extends \Magento\Checkout\Controller\Cart ); } } else { - if ($isCodeLengthValid && $couponCode == $cartQuote->getCouponCode()) { + if ($isCodeLengthValid && $coupon->getId() && $couponCode == $cartQuote->getCouponCode()) { $this->messageManager->addSuccess( __( 'You used coupon code "%1".', diff --git a/app/code/Magento/Checkout/Test/Unit/Controller/Cart/CouponPostTest.php b/app/code/Magento/Checkout/Test/Unit/Controller/Cart/CouponPostTest.php index 16ffb7c2b1437da5e7ffadcc6ebe2fc4b3c479d3..93100df3d8c32182912d59f96f9149200f5f0139 100644 --- a/app/code/Magento/Checkout/Test/Unit/Controller/Cart/CouponPostTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Controller/Cart/CouponPostTest.php @@ -69,6 +69,16 @@ class CouponPostTest extends \PHPUnit_Framework_TestCase */ protected $quoteRepository; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $redirect; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $redirectFactory; + /** * @return void */ @@ -204,6 +214,12 @@ class CouponPostTest extends \PHPUnit_Framework_TestCase ->method('getCouponCode') ->willReturn('OLDCODE'); + $coupon = $this->getMock(\Magento\SalesRule\Model\Coupon::class, [], [], '', false); + $this->couponFactory->expects($this->once()) + ->method('create') + ->willReturn($coupon); + $coupon->expects($this->once())->method('load')->willReturnSelf(); + $coupon->expects($this->once())->method('getId')->willReturn(1); $this->quote->expects($this->any()) ->method('getItemsCount') ->willReturn(1); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js b/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js index e06b8922b2252fd497db66a79db35af8c543db09..eba77927be79ea6189884f412be03be7ec7a76be 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js @@ -7,9 +7,10 @@ define([ 'jquery', 'mage/template', + 'underscore', 'jquery/ui', 'mage/validation' -], function ($, mageTemplate) { +], function ($, mageTemplate, _) { 'use strict'; $.widget('mage.regionUpdater', { @@ -124,6 +125,8 @@ define([ * @private */ _clearError: function () { + var args = ['clearError', this.options.regionListId, this.options.regionInputId, this.options.postcodeId]; + if (this.options.clearError && typeof this.options.clearError === 'function') { this.options.clearError.call(this); } else { @@ -133,8 +136,8 @@ define([ this.options.form = $(this.options.form); - this.options.form && this.options.form.data('validator') && this.options.form.validation('clearError', - this.options.regionListId, this.options.regionInputId, this.options.postcodeId); + this.options.form && this.options.form.data('validator') && + this.options.form.validation.apply(this.options.form, _.compact(args)); // Clean up errors on region & zip fix $(this.options.regionInputId).removeClass('mage-error').parent().find('[generated]').remove(); diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php index 0b8a4aee9feced6e4f104208b7563bda16b6305c..0bd2f23418221770d4562eb67d6af9d3e8bd4646 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php @@ -1287,4 +1287,19 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType } return $this->catalogConfig; } + + /** + * @inheritdoc + */ + public function isPossibleBuyFromList($product) + { + $isAllCustomOptionsDisplayed = true; + foreach ($this->getConfigurableAttributes($product) as $attribute) { + $eavAttribute = $attribute->getProductAttribute(); + + $isAllCustomOptionsDisplayed = ($isAllCustomOptionsDisplayed && $eavAttribute->getUsedInProductListing()); + } + + return $isAllCustomOptionsDisplayed; + } } diff --git a/app/code/Magento/Eav/Model/AttributeManagement.php b/app/code/Magento/Eav/Model/AttributeManagement.php index 8d8674bcca0e7886d4a174840a7d55dea5bef8a4..102aafbd39fb1ba473dc1a346a857ccf695a5dab 100644 --- a/app/code/Magento/Eav/Model/AttributeManagement.php +++ b/app/code/Magento/Eav/Model/AttributeManagement.php @@ -6,10 +6,14 @@ */ namespace Magento\Eav\Model; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class AttributeManagement implements \Magento\Eav\Api\AttributeManagementInterface { /** @@ -19,6 +23,7 @@ class AttributeManagement implements \Magento\Eav\Api\AttributeManagementInterfa /** * @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection + * @deprecated please use instead \Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory */ protected $attributeCollection; @@ -47,6 +52,11 @@ class AttributeManagement implements \Magento\Eav\Api\AttributeManagementInterfa */ protected $attributeResource; + /** + * @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory + */ + private $attributeCollectionFactory; + /** * @param \Magento\Eav\Api\AttributeSetRepositoryInterface $setRepository * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection $attributeCollection @@ -154,11 +164,26 @@ class AttributeManagement implements \Magento\Eav\Api\AttributeManagementInterfa if (!$attributeSet->getAttributeSetId() || $attributeSet->getEntityTypeId() != $requiredEntityTypeId) { throw NoSuchEntityException::singleField('attributeSetId', $attributeSetId); } - - $attributeCollection = $this->attributeCollection - ->setAttributeSetFilter($attributeSet->getAttributeSetId()) - ->load(); + /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection $attributeCollection */ + $attributeCollection = $this->getCollectionFactory()->create(); + $attributeCollection->setAttributeSetFilter($attributeSet->getAttributeSetId())->load(); return $attributeCollection->getItems(); } + + /** + * Retrieve collection factory + * + * @deprecated + * @return \Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory + */ + private function getCollectionFactory() + { + if ($this->attributeCollectionFactory === null) { + $this->attributeCollectionFactory = ObjectManager::getInstance()->create( + \Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory::class + ); + } + return $this->attributeCollectionFactory; + } } diff --git a/app/code/Magento/Eav/Test/Unit/Model/AttributeManagementTest.php b/app/code/Magento/Eav/Test/Unit/Model/AttributeManagementTest.php index 88118e0b0f70fc54241d76b3895c644c5bd4a616..c45c575dffc2fa9fd87cf9e226ef06ceaa0ce2e2 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/AttributeManagementTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/AttributeManagementTest.php @@ -371,6 +371,24 @@ class AttributeManagementTest extends \PHPUnit_Framework_TestCase $entityType = 'type'; $attributeSetId = 148; + $attributeCollectionFactoryMock = $this->getMock( + \Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory::class, + ['create'], + [], + '', + false + ); + $attributeCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->attributeCollectionMock); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $objectManager->setBackwardCompatibleProperty( + $this->model, + 'attributeCollectionFactory', + $attributeCollectionFactoryMock + ); + $attributeSetMock = $this->getMock(\Magento\Eav\Api\Data\AttributeSetInterface::class, [], [], '', false); $this->setRepositoryMock->expects($this->once()) ->method('get') diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php index 36f1310079ed534d928fa03be511a64265f71dc5..ac3ffdc3d622c956074b3fc174df6c24e4cabff3 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php @@ -217,9 +217,9 @@ class CreditmemoLoader extends DataObject foreach ($creditmemo->getAllItems() as $creditmemoItem) { $orderItem = $creditmemoItem->getOrderItem(); $parentId = $orderItem->getParentItemId(); - if (isset($backToStock[$orderItem->getId()])) { + if ($parentId && isset($backToStock[$parentId]) && $backToStock[$parentId]) { $creditmemoItem->setBackToStock(true); - } elseif ($orderItem->getParentItem() && isset($backToStock[$parentId]) && $backToStock[$parentId]) { + } elseif (isset($backToStock[$orderItem->getId()])) { $creditmemoItem->setBackToStock(true); } elseif (empty($savedData)) { $creditmemoItem->setBackToStock( diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php index 21104933a51d6d8fda5d225ff4b879a07def3d20..ff687074e4a66cc50c457c685fc1757d1529dcb6 100644 --- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php +++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php @@ -3,7 +3,6 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Sales\Model\Order; /** @@ -23,6 +22,11 @@ class CreditmemoFactory */ protected $taxConfig; + /** + * @var \Magento\Framework\Unserialize\Unserialize + */ + protected $unserialize; + /** * Factory constructor * @@ -57,7 +61,12 @@ class CreditmemoFactory $item = $this->convertor->itemToCreditmemoItem($orderItem); if ($orderItem->isDummy()) { - $qty = 1; + if (isset($data['qtys'][$orderItem->getParentItemId()])) { + $parentQty = $data['qtys'][$orderItem->getParentItemId()]; + } else { + $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1; + } + $qty = $this->calculateProductOptions($orderItem, $parentQty); $orderItem->setLockedDoShip(true); } else { if (isset($qtys[$orderItem->getId()])) { @@ -132,7 +141,12 @@ class CreditmemoFactory $item = $this->convertor->itemToCreditmemoItem($orderItem); if ($orderItem->isDummy()) { - $qty = 1; + if (isset($data['qtys'][$orderItem->getParentItemId()])) { + $parentQty = $data['qtys'][$orderItem->getParentItemId()]; + } else { + $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1; + } + $qty = $this->calculateProductOptions($orderItem, $parentQty); } else { if (isset($qtys[$orderItem->getId()])) { $qty = (double)$qtys[$orderItem->getId()]; @@ -245,4 +259,38 @@ class CreditmemoFactory $creditmemo->setAdjustmentNegative($data['adjustment_negative']); } } + + /** + * @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem + * @param array $qtys + * @return int + */ + private function calculateProductOptions(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, $parentQty) + { + $qty = $parentQty; + $productOptions = $orderItem->getProductOptions(); + if (isset($productOptions['bundle_selection_attributes'])) { + $bundleSelectionAttributes = $this->getUnserialize() + ->unserialize($productOptions['bundle_selection_attributes']); + if ($bundleSelectionAttributes) { + $qty = $bundleSelectionAttributes['qty'] * $parentQty; + } + } + return $qty; + } + + /** + * Get Unserialize + * + * @return \Magento\Framework\Unserialize\Unserialize + * @deprecated + */ + private function getUnserialize() + { + if (!$this->unserialize) { + $this->unserialize = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Unserialize\Unserialize::class); + } + return $this->unserialize; + } } diff --git a/app/code/Magento/Sales/Model/Order/Payment.php b/app/code/Magento/Sales/Model/Order/Payment.php index a0f56d6ea9a73ea02d4c852ef6ac4831be29b574..3cd5ecde21366c87d4ee746a0ddc1b453ec0bf95 100644 --- a/app/code/Magento/Sales/Model/Order/Payment.php +++ b/app/code/Magento/Sales/Model/Order/Payment.php @@ -1289,7 +1289,7 @@ class Payment extends Info implements OrderPaymentInterface */ public function isCaptureFinal($amountToCapture) { - $total = $this->getOrder()->getTotalDue(); + $total = $this->getOrder()->getBaseTotalDue(); return $this->formatAmount($total, true) == $this->formatAmount($amountToCapture, true); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php index f97e3be1dcb6dcb9ea6383efec081517751325b5..7f058b7c05053646af0272e5b4f206105b8b45aa 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php @@ -1548,7 +1548,7 @@ class PaymentTest extends \PHPUnit_Framework_TestCase $partialAmount = 12.00; $this->orderMock->expects(static::exactly(2)) - ->method('getTotalDue') + ->method('getBaseTotalDue') ->willReturn($amount); static::assertFalse($this->payment->isCaptureFinal($partialAmount)); diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml index 59bb31a94fa0cadadf177f695271c1efeaa69aa6..a8ccf82c5fe06030055381d9c13228661308e04e 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml @@ -66,7 +66,13 @@ <?php endif; ?> <?php if ($block->canDisplayPrice()): ?> - <td class="col-price"><?php /* @noEscape */ echo $block->getItemPrice($_item) ?></td> + <td class="col-price"> + <?php if ($block->getDataId() == 'cart'): ?> + <?php /* @noEscape */ echo $block->getItemPrice($_item->getProduct()) ?> + <?php else: ?> + <?php /* @noEscape */ echo $block->getItemPrice($_item) ?> + <?php endif; ?> + </td> <?php endif; ?> <?php if ($block->canRemoveItems()): ?> diff --git a/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php b/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php index 7752d7131031cf0daa63f4c8b8bf49609e3090ed..3680bbb3a1eaefa3ee822eefd99b7b21b320a3f8 100644 --- a/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php +++ b/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php @@ -6,7 +6,6 @@ namespace Magento\SalesInventory\Model\Order; use Magento\Sales\Api\Data\CreditmemoInterface; -use Magento\Sales\Api\Data\CreditmemoItemInterface; use Magento\Sales\Api\Data\OrderInterface; /** @@ -29,52 +28,35 @@ class ReturnProcessor */ private $priceIndexer; - /** - * @var \Magento\Sales\Api\CreditmemoRepositoryInterface - */ - private $creditmemoRepository; - /** * @var \Magento\Store\Model\StoreManagerInterface */ private $storeManager; - /** - * @var \Magento\Sales\Api\OrderRepositoryInterface - */ - private $orderRepository; - /** * @var \Magento\Sales\Api\OrderItemRepositoryInterface */ private $orderItemRepository; /** - * ReturnToStockPlugin constructor. - * @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration + * ReturnProcessor constructor. * @param \Magento\CatalogInventory\Api\StockManagementInterface $stockManagement * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexer * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer - * @param \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository * @param \Magento\Store\Model\StoreManagerInterface $storeManager - * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository * @param \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository */ public function __construct( \Magento\CatalogInventory\Api\StockManagementInterface $stockManagement, \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexer, \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer, - \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository, \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Sales\Api\OrderRepositoryInterface $orderRepository, \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository ) { $this->stockManagement = $stockManagement; $this->stockIndexerProcessor = $stockIndexer; $this->priceIndexer = $priceIndexer; - $this->creditmemoRepository = $creditmemoRepository; $this->storeManager = $storeManager; - $this->orderRepository = $orderRepository; $this->orderItemRepository = $orderItemRepository; } @@ -82,22 +64,22 @@ class ReturnProcessor * @param CreditmemoInterface $creditmemo * @param OrderInterface $order * @param array $returnToStockItems + * @param bool $isAutoReturn * @return void */ public function execute( CreditmemoInterface $creditmemo, OrderInterface $order, - array $returnToStockItems = [] + array $returnToStockItems = [], + $isAutoReturn = false ) { $itemsToUpdate = []; foreach ($creditmemo->getItems() as $item) { - $qty = $item->getQty(); $productId = $item->getProductId(); $orderItem = $this->orderItemRepository->get($item->getOrderItemId()); $parentItemId = $orderItem->getParentItemId(); - if ($this->canReturnItem($item, $qty, $parentItemId, $returnToStockItems)) { - $parentItem = $parentItemId ? $this->getItemByOrderId($creditmemo, $parentItemId) : false; - $qty = $parentItem ? $parentItem->getQty() * $qty : $qty; + $qty = $item->getQty(); + if ($isAutoReturn || $this->canReturnItem($item, $qty, $parentItemId, $returnToStockItems)) { if (isset($itemsToUpdate[$productId])) { $itemsToUpdate[$productId] += $qty; } else { @@ -122,21 +104,6 @@ class ReturnProcessor } } - /** - * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo - * @param int $parentItemId - * @return bool|CreditmemoItemInterface - */ - private function getItemByOrderId(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo, $parentItemId) - { - foreach ($creditmemo->getItems() as $item) { - if ($item->getOrderItemId() == $parentItemId) { - return $item; - } - } - return false; - } - /** * @param \Magento\Sales\Api\Data\CreditmemoItemInterface $item * @param int $qty diff --git a/app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php b/app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php similarity index 57% rename from app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php rename to app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php index 9702bfc7cfe425b2c8987c1aec4e86430e1d62ac..acdebcf976a2eead77eb6074611968a9831cd524 100644 --- a/app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php +++ b/app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php @@ -4,54 +4,74 @@ * See COPYING.txt for license details. */ -namespace Magento\CatalogInventory\Observer; +namespace Magento\SalesInventory\Observer; use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockManagementInterface; use Magento\Framework\Event\Observer as EventObserver; use Magento\Framework\Event\ObserverInterface; +use Magento\Sales\Model\OrderRepository; +use Magento\SalesInventory\Model\Order\ReturnProcessor; /** * Catalog inventory module observer + * @deprecated */ class RefundOrderInventoryObserver implements ObserverInterface { /** * @var StockConfigurationInterface */ - protected $stockConfiguration; + private $stockConfiguration; /** * @var StockManagementInterface */ - protected $stockManagement; + private $stockManagement; /** * @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor */ - protected $stockIndexerProcessor; + private $stockIndexerProcessor; /** * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor */ - protected $priceIndexer; + private $priceIndexer; /** + * @var \Magento\SalesInventory\Model\Order\ReturnProcessor + */ + private $returnProcessor; + + /** + * @var \Magento\Sales\Api\OrderRepositoryInterface + */ + private $orderRepository; + + /** + * RefundOrderInventoryObserver constructor. * @param StockConfigurationInterface $stockConfiguration * @param StockManagementInterface $stockManagement * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer + * @param ReturnProcessor $returnProcessor + * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository */ public function __construct( StockConfigurationInterface $stockConfiguration, StockManagementInterface $stockManagement, \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor, - \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer + \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer, + \Magento\SalesInventory\Model\Order\ReturnProcessor $returnProcessor, + \Magento\Sales\Api\OrderRepositoryInterface $orderRepository ) { $this->stockConfiguration = $stockConfiguration; $this->stockManagement = $stockManagement; $this->stockIndexerProcessor = $stockIndexerProcessor; $this->priceIndexer = $priceIndexer; + $this->returnProcessor = $returnProcessor; + $this->orderRepository = $orderRepository; } /** @@ -64,31 +84,18 @@ class RefundOrderInventoryObserver implements ObserverInterface { /* @var $creditmemo \Magento\Sales\Model\Order\Creditmemo */ $creditmemo = $observer->getEvent()->getCreditmemo(); - $itemsToUpdate = []; - foreach ($creditmemo->getAllItems() as $item) { - $qty = $item->getQty(); - if (($item->getBackToStock() && $qty) || $this->stockConfiguration->isAutoReturnEnabled()) { - $productId = $item->getProductId(); - $parentItemId = $item->getOrderItem()->getParentItemId(); - /* @var $parentItem \Magento\Sales\Model\Order\Creditmemo\Item */ - $parentItem = $parentItemId ? $creditmemo->getItemByOrderId($parentItemId) : false; - $qty = $parentItem ? $parentItem->getQty() * $qty : $qty; - if (isset($itemsToUpdate[$productId])) { - $itemsToUpdate[$productId] += $qty; - } else { - $itemsToUpdate[$productId] = $qty; - } + $order = $this->orderRepository->get($creditmemo->getOrderId()); + $returnToStockItems = []; + foreach ($creditmemo->getItems() as $item) { + if ($item->getBackToStock()) { + $returnToStockItems[] = $item->getOrderItemId(); } } - if (!empty($itemsToUpdate)) { - $this->stockManagement->revertProductsSale( - $itemsToUpdate, - $creditmemo->getStore()->getWebsiteId() - ); - - $updatedItemIds = array_keys($itemsToUpdate); - $this->stockIndexerProcessor->reindexList($updatedItemIds); - $this->priceIndexer->reindexList($updatedItemIds); - } + $this->returnProcessor->execute( + $creditmemo, + $order, + $returnToStockItems, + $this->stockConfiguration->isAutoReturnEnabled() + ); } } diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php index 523759d54645a1e2db471db948fa116cf59cd32e..efa3bff32c0fa2b40c3a9a57ec04cb1ec5c9f257 100644 --- a/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php +++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php @@ -5,9 +5,7 @@ */ namespace Magento\SalesInventory\Test\Unit\Model\Order; -use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockManagementInterface; -use Magento\Sales\Api\CreditmemoRepositoryInterface; use Magento\Sales\Api\Data\CreditmemoInterface; use Magento\Sales\Api\Data\CreditmemoItemInterface; use Magento\Sales\Api\Data\OrderInterface; @@ -49,21 +47,11 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase */ private $priceIndexerMock; - /** - * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoRepositoryInterface - */ - private $creditmemoRepositoryMock; - /** * @var \PHPUnit_Framework_MockObject_MockObject|StoreManagerInterface */ private $storeManagerMock; - /** - * @var \PHPUnit_Framework_MockObject_MockObject|OrderRepositoryInterface - */ - private $orderRepositoryMock; - /** * @var \PHPUnit_Framework_MockObject_MockObject|OrderItemRepositoryInterface */ @@ -95,13 +83,10 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase $this->priceIndexerMock = $this->getMockBuilder(\Magento\Catalog\Model\Indexer\Product\Price\Processor::class) ->disableOriginalConstructor() ->getMock(); - $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class) - ->disableOriginalConstructor() - ->getMock(); $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) + $this->orderItemRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) ->disableOriginalConstructor() ->getMock(); $this->orderItemRepositoryMock = $this->getMockBuilder(OrderItemRepositoryInterface::class) @@ -127,9 +112,7 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase $this->stockManagementMock, $this->stockIndexerProcessorMock, $this->priceIndexerMock, - $this->creditmemoRepositoryMock, $this->storeManagerMock, - $this->orderRepositoryMock, $this->orderItemRepositoryMock ); } @@ -139,6 +122,7 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase $orderItemId = 99; $productId = 50; $returnToStockItems = [$orderItemId]; + $parentItemId = 52; $qty = 1; $storeId = 0; $webSiteId = 10; @@ -147,10 +131,6 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase ->method('getItems') ->willReturn([$this->creditmemoItemMock]); - $this->creditmemoItemMock->expects($this->once()) - ->method('getQty') - ->willReturn($qty); - $this->creditmemoItemMock->expects($this->exactly(2)) ->method('getOrderItemId') ->willReturn($orderItemId); @@ -190,6 +170,14 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase ->method('reindexList') ->with([$productId]); + $this->orderItemMock->expects($this->once()) + ->method('getParentItemId') + ->willReturn($parentItemId); + + $this->creditmemoItemMock->expects($this->once()) + ->method('getQty') + ->willReturn($qty); + $this->returnProcessor->execute($this->creditmemoMock, $this->orderMock, $returnToStockItems); } } diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php b/app/code/Magento/SalesInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php similarity index 65% rename from app/code/Magento/CatalogInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php rename to app/code/Magento/SalesInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php index e440ed3380498a0c8d0deb9fb4edbd68a5d2c295..4e553493d07f63ed9f7d0a2d0d0ec7129d7580e7 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php +++ b/app/code/Magento/SalesInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php @@ -3,9 +3,12 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\CatalogInventory\Test\Unit\Observer; +namespace Magento\SalesInventory\Test\Unit\Observer; -use Magento\CatalogInventory\Observer\RefundOrderInventoryObserver; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Model\OrderRepository; +use Magento\SalesInventory\Model\Order\ReturnProcessor; +use Magento\SalesInventory\Observer\RefundOrderInventoryObserver; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -47,6 +50,26 @@ class RefundOrderInventoryObserverTest extends \PHPUnit_Framework_TestCase */ protected $eventObserver; + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + protected $objectManagerHelper; + + /** + * @var OrderRepository|\PHPUnit_Framework_MockObject_MockObject + */ + protected $orderRepositoryMock; + + /** + * @var ReturnProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + protected $returnProcessorMock; + + /** + * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $orderMock; + protected function setUp() { $this->stockIndexerProcessor = $this->getMock( @@ -93,8 +116,22 @@ class RefundOrderInventoryObserverTest extends \PHPUnit_Framework_TestCase ->method('getEvent') ->will($this->returnValue($this->event)); - $this->observer = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( - \Magento\CatalogInventory\Observer\RefundOrderInventoryObserver::class, + $this->orderRepositoryMock = $this->getMockBuilder(OrderRepository::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->returnProcessorMock = $this->getMockBuilder(ReturnProcessor::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->observer = $this->objectManagerHelper->getObject( + \Magento\SalesInventory\Observer\RefundOrderInventoryObserver::class, [ 'stockConfiguration' => $this->stockConfiguration, 'stockManagement' => $this->stockManagement, @@ -102,83 +139,67 @@ class RefundOrderInventoryObserverTest extends \PHPUnit_Framework_TestCase 'priceIndexer' => $this->priceIndexer, ] ); + + $this->objectManagerHelper->setBackwardCompatibleProperty( + $this->observer, + 'orderRepository', + $this->orderRepositoryMock + ); + $this->objectManagerHelper->setBackwardCompatibleProperty( + $this->observer, + 'returnProcessor', + $this->returnProcessorMock + ); } public function testRefundOrderInventory() { - $websiteId = 0; $ids = ['1', '14']; $items = []; $isAutoReturnEnabled = true; - $store = $this->getMock( - \Magento\Store\Model\Store::class, - ['getWebsiteId'], - [], - '', - false - ); - $store->expects($this->once())->method('getWebsiteId')->will($this->returnValue($websiteId)); + $creditMemo = $this->getMock(\Magento\Sales\Model\Order\Creditmemo::class, [], [], '', false); - $itemsToUpdate = []; foreach ($ids as $id) { $item = $this->getCreditMemoItem($id); $items[] = $item; - $itemsToUpdate[$item->getProductId()] = $item->getQty(); } - $creditMemo = $this->getMock(\Magento\Sales\Model\Order\Creditmemo::class, [], [], '', false); + $creditMemo->expects($this->once()) - ->method('getAllItems') + ->method('getItems') ->will($this->returnValue($items)); - $creditMemo->expects($this->once())->method('getStore')->will($this->returnValue($store)); $this->stockConfiguration->expects($this->any()) ->method('isAutoReturnEnabled') ->will($this->returnValue($isAutoReturnEnabled)); - $this->stockManagement->expects($this->once()) - ->method('revertProductsSale') - ->with($itemsToUpdate, $websiteId); - - $this->stockIndexerProcessor->expects($this->once()) - ->method('reindexList') - ->with($ids); - - $this->priceIndexer->expects($this->once()) - ->method('reindexList') - ->with($ids); - $this->event->expects($this->once()) ->method('getCreditmemo') ->will($this->returnValue($creditMemo)); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + + $this->returnProcessorMock->expects($this->once()) + ->method('execute') + ->with($creditMemo, $this->orderMock, $ids, $isAutoReturnEnabled); + $this->observer->execute($this->eventObserver); } private function getCreditMemoItem($productId) { - $parentItemId = false; $backToStock = true; - $qty = 1; $item = $this->getMock( \Magento\Sales\Model\Order\Creditmemo\Item::class, - ['getProductId', 'getOrderItem', 'getBackToStock', 'getQty', '__wakeup'], - [], - '', - false - ); - $orderItem = $this->getMock( - \Magento\Sales\Model\Order\Item::class, - ['getParentItemId', '__wakeup'], + ['getOrderItemId', 'getBackToStock', 'getQty', '__wakeup'], [], '', false ); - $orderItem->expects($this->any())->method('getParentItemId')->willReturn($parentItemId); - $item->expects($this->any())->method('getOrderItem')->willReturn($orderItem); - $item->expects($this->any())->method('getProductId')->will($this->returnValue($productId)); $item->expects($this->any())->method('getBackToStock')->willReturn($backToStock); - $item->expects($this->any())->method('getQty')->willReturn($qty); + $item->expects($this->any())->method('getOrderItemId')->willReturn($productId); return $item; } } diff --git a/app/code/Magento/SalesInventory/etc/events.xml b/app/code/Magento/SalesInventory/etc/events.xml new file mode 100644 index 0000000000000000000000000000000000000000..a71ed7f8a28a16a4ded03e507876757ec94f436c --- /dev/null +++ b/app/code/Magento/SalesInventory/etc/events.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> + <event name="sales_order_creditmemo_save_after"> + <observer name="inventory" instance="Magento\SalesInventory\Observer\RefundOrderInventoryObserver"/> + </event> +</config> diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index 68a18ef8be6a1b2d51403acac0ebaca1ecc83996..a973a822c4101671faa0fe57925a0e9b0c5b2f2a 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -63,6 +63,13 @@ class Data */ protected $imageHelper; + /** + * Product metadata pool + * + * @var \Magento\Framework\EntityManager\MetadataPool + */ + private $metadataPool; + /** * Data key which should populated to Attribute entity from "additional_data" field * @@ -196,7 +203,13 @@ class Data } $productCollection = $this->productCollectionFactory->create(); - $this->addFilterByParent($productCollection, $parentProduct->getId()); + + $productLinkedFiled = $this->getMetadataPool() + ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); + $parentId = $parentProduct->getData($productLinkedFiled); + + $this->addFilterByParent($productCollection, $parentId); $configurableAttributes = $this->getAttributesFromConfigurable($parentProduct); $allAttributesArray = []; @@ -491,4 +504,19 @@ class Data } return $attribute->getData(Swatch::SWATCH_INPUT_TYPE_KEY) == Swatch::SWATCH_INPUT_TYPE_TEXT; } + + /** + * Get product metadata pool. + * + * @return \Magento\Framework\EntityManager\MetadataPool + * @deprecared + */ + protected function getMetadataPool() + { + if (!$this->metadataPool) { + $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\EntityManager\MetadataPool::class); + } + return $this->metadataPool; + } } diff --git a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php index 6cf79dae309a583aca3ced31bd1411eb9d53b27b..e5f2f887836eff5ad73ca95602d4d7aec411150e 100644 --- a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php @@ -46,6 +46,9 @@ class DataTest extends \PHPUnit_Framework_TestCase /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Api\ProductRepositoryInterface */ protected $productRepoMock; + /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\EntityManager\MetadataPool*/ + private $metaDataPoolMock; + protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -108,7 +111,13 @@ class DataTest extends \PHPUnit_Framework_TestCase '', false ); - + $this->metaDataPoolMock = $this->getMock( + \Magento\Framework\EntityManager\MetadataPool::class, + [], + [], + '', + false + ); $this->swatchHelperObject = $this->objectManager->getObject( \Magento\Swatches\Helper\Data::class, [ @@ -120,6 +129,11 @@ class DataTest extends \PHPUnit_Framework_TestCase 'imageHelper' => $this->imageHelperMock, ] ); + $this->objectManager->setBackwardCompatibleProperty( + $this->swatchHelperObject, + 'metadataPool', + $this->metaDataPoolMock + ); } public function dataForAdditionalData() @@ -246,12 +260,16 @@ class DataTest extends \PHPUnit_Framework_TestCase */ public function testLoadVariationByFallback($product) { + $metadataMock = $this->getMock(\Magento\Framework\EntityManager\EntityMetadataInterface::class); + $this->metaDataPoolMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $metadataMock->expects($this->once())->method('getLinkField')->willReturn('id'); + $this->getSwatchAttributes($product); $this->prepareVariationCollection(); $this->productCollectionMock->method('getFirstItem')->willReturn($this->productMock); - $this->productMock->method('getId')->willReturn(95); + $this->productMock->method('getData')->with('id')->willReturn(95); $this->productModelFactoryMock->method('create')->willReturn($this->productMock); $this->productMock->method('load')->with(95)->will($this->returnSelf()); 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 86046fdce4b6ee3d264d86f94f3a7dcfbf4b13b3..9c3274627b984cc093ecf5f39c54190ead2412fa 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 @@ -7,15 +7,17 @@ <?php /** @var $block \Magento\Swatches\Block\Product\Renderer\Configurable */ ?> <div class="swatch-opt-<?php /* @escapeNotVerified */ echo $block->getProduct()->getId() ?>"></div> <script> - require(["jquery", "jquery/ui", "Magento_Swatches/js/swatch-renderer"], function ($) { - $('.swatch-opt-<?php /* @escapeNotVerified */ echo $block->getProduct()->getId() ?>').SwatchRenderer({ - selectorProduct: '.product-item-details', - onlySwatches: true, - enableControlLabel: false, - numberToShow: <?php /* @escapeNotVerified */ echo $block->getNumberSwatchesPerProduct(); ?>, - jsonConfig: <?php /* @escapeNotVerified */ echo $block->getJsonConfig(); ?>, - jsonSwatchConfig: <?php /* @escapeNotVerified */ echo $block->getJsonSwatchConfig(); ?>, - mediaCallback: '<?php /* @escapeNotVerified */ echo $block->getMediaCallback() ?>' - }); + require( + ["jquery", "jquery/ui", "Magento_Swatches/js/swatch-renderer", "Magento_Swatches/js/catalog-add-to-cart"], + function ($) { + $('.swatch-opt-<?php /* @escapeNotVerified */ echo $block->getProduct()->getId() ?>').SwatchRenderer({ + selectorProduct: '.product-item-details', + onlySwatches: true, + enableControlLabel: false, + numberToShow: <?php /* @escapeNotVerified */ echo $block->getNumberSwatchesPerProduct(); ?>, + jsonConfig: <?php /* @escapeNotVerified */ echo $block->getJsonConfig(); ?>, + jsonSwatchConfig: <?php /* @escapeNotVerified */ echo $block->getJsonSwatchConfig(); ?>, + mediaCallback: '<?php /* @escapeNotVerified */ echo $block->getMediaCallback() ?>' + }); }); </script> diff --git a/app/code/Magento/Swatches/view/frontend/web/js/catalog-add-to-cart.js b/app/code/Magento/Swatches/view/frontend/web/js/catalog-add-to-cart.js new file mode 100644 index 0000000000000000000000000000000000000000..7900ff67b09be952f13bcfd1bd88842327dd0db4 --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/web/js/catalog-add-to-cart.js @@ -0,0 +1,17 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +require([ + 'jquery' +], function ($) { + 'use strict'; + + $('body').on('catalogCategoryAddToCartRedirect', function (event, data) { + $(data.form).find('[name*="super"]').each(function (index, item) { + var $item = $(item); + + data.redirectParameters.push($item.attr('data-attr-name') + '=' + $item.val()); + }); + }); +}); 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 54e207c335ffb5b6a007a7774df4e2c4a0760628..452c9b6f94d3c60e83bd35a5a932c6b5f8a9092f 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 @@ -264,6 +264,8 @@ define([ */ _init: function () { if (this.options.jsonConfig !== '' && this.options.jsonSwatchConfig !== '') { + // store unsorted attributes + this.options.jsonConfig.mappedAttributes = _.clone(this.options.jsonConfig.attributes); this._sortAttributes(); this._RenderControls(); $(this.element).trigger('swatch.initialized'); @@ -617,6 +619,7 @@ define([ $parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected'); $label.text($this.attr('option-label')); $input.val($this.attr('option-id')); + $input.attr('data-attr-name', this._getAttributeCodeById(attributeId)); $this.addClass('selected'); $widget._toggleCheckedAttributes($this, $wrapper); } @@ -633,6 +636,19 @@ define([ $input.trigger('change'); }, + /** + * Get human readable attribute code (eg. size, color) by it ID from configuration + * + * @param {Number} attributeId + * @returns {*} + * @private + */ + _getAttributeCodeById: function (attributeId) { + var attribute = this.options.jsonConfig.mappedAttributes[attributeId]; + + return attribute ? attribute.code : attributeId; + }, + /** * Toggle accessibility attributes * @@ -1104,7 +1120,7 @@ define([ params = $.parseQuery(window.location.href.substr(hashIndex + 1)); selectedAttributes = _.invert(_.mapObject(_.invert(params), function (attributeId) { - var attribute = this.options.jsonConfig.attributes[attributeId]; + var attribute = this.options.jsonConfig.mappedAttributes[attributeId]; return attribute ? attribute.code : attributeId; }.bind(this))); diff --git a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/ThemeId.php b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/ThemeId.php index f5197dd7d0435d672023a0027d7bbb7674036abb..dc048d41612b800c9d291b5067b0106bb1fbf079 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/ThemeId.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/ThemeId.php @@ -10,6 +10,10 @@ */ namespace Magento\Widget\Model\ResourceModel\Widget\Instance\Options; +/** + * @deprecated created new class that correctly loads theme options and whose name follows naming convention + * @see \Magento\Widget\Model\ResourceModel\Widget\Instance\Options\Themes + */ class ThemeId implements \Magento\Framework\Option\ArrayInterface { /** diff --git a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Themes.php b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Themes.php new file mode 100644 index 0000000000000000000000000000000000000000..403dfeb40ff2ea3330440c0a22db4247e9a5e377 --- /dev/null +++ b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Themes.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Widget\Model\ResourceModel\Widget\Instance\Options; + +use Magento\Framework\Data\OptionSourceInterface; +use Magento\Theme\Model\ResourceModel\Theme\CollectionFactory as ThemeCollectionFactory; + +/** + * Option source of the widget theme property. + * + * Can be used as a data provider for UI components that shows possible themes as a list. + */ +class Themes implements OptionSourceInterface +{ + /** + * @var ThemeCollectionFactory + */ + private $themeCollectionFactory; + + /** + * @param ThemeCollectionFactory $themeCollectionFactory + */ + public function __construct(ThemeCollectionFactory $themeCollectionFactory) + { + $this->themeCollectionFactory = $themeCollectionFactory; + } + + /** + * Return array of options as value-label pairs + * + * @return array Format: array('<theme ID>' => '<theme label>', ...) + */ + public function toOptionArray() + { + // Load only visible themes that are used in frontend area + return $this->themeCollectionFactory->create()->loadRegisteredThemes()->toOptionHash(); + } +} diff --git a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Widget/Instance/Options/ThemesTest.php b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Widget/Instance/Options/ThemesTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e3854a599013298e0b3bbd6439183611d14b95d3 --- /dev/null +++ b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Widget/Instance/Options/ThemesTest.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Widget\Test\Unit\Model\ResourceModel\Widget\Instance\Options; + +use Magento\Widget\Model\ResourceModel\Widget\Instance\Options\Themes; +use Magento\Theme\Model\ResourceModel\Theme\Collection as ThemeCollection; +use Magento\Theme\Model\ResourceModel\Theme\CollectionFactory as ThemeCollectionFactory; + +/** + * Test class for \Magento\Widget\Model\ResourceModel\Widget\Instance\Options\Themes + */ +class ThemesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Themes + */ + private $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $themeCollectionFactoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $themeCollectionMock; + + protected function setUp() + { + $this->themeCollectionMock = $this->getMock(ThemeCollection::class, [], [], '', false); + $this->themeCollectionFactoryMock = $this->getMock(ThemeCollectionFactory::class, ['create'], [], '', false); + $this->model = new Themes( + $this->themeCollectionFactoryMock + ); + } + + public function testToOptionArray() + { + $expectedResult = [ + 1 => 'Theme Label', + ]; + $this->themeCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->themeCollectionMock); + + $this->themeCollectionMock->expects($this->once())->method('loadRegisteredThemes')->willReturnSelf(); + $this->themeCollectionMock->expects($this->once())->method('toOptionHash')->willReturn($expectedResult); + + $this->assertEquals($expectedResult, $this->model->toOptionArray()); + } +} diff --git a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml index 2d9cf935afa0d4281e46f997e22465285f69e53d..db73e302f4a7629e380292308cce534693560d99 100644 --- a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml +++ b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml @@ -52,7 +52,7 @@ <argument name="header" xsi:type="string" translate="true">Design Theme</argument> <argument name="index" xsi:type="string">theme_id</argument> <argument name="type" xsi:type="string">options</argument> - <argument name="options" xsi:type="options" model="Magento\Widget\Model\ResourceModel\Widget\Instance\Options\ThemeId"/> + <argument name="options" xsi:type="options" model="Magento\Widget\Model\ResourceModel\Widget\Instance\Options\Themes"/> <argument name="with_empty" xsi:type="string">1</argument> </arguments> </block> diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less index 3804721026db50a77ebaf752c75f5dc35a23cf09..d861d4dcae256222cb30cc81ee21359a40e12582 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less @@ -23,8 +23,7 @@ & when (@media-common = true) { - .checkout-index-index, - .checkout-onepage-success { + .checkout-index-index { .page-title-wrapper { &:extend(.abs-visually-hidden all); } @@ -61,6 +60,14 @@ margin-left: 0; } } + + .checkout-onepage-success { + &:extend(.abs-add-clearfix all); + + .print { + display: none; + } + } } // @@ -87,4 +94,12 @@ .lib-layout-column(2, 1, @checkout-wrapper__columns); padding-right: @indent__l; } + + .checkout-onepage-success { + .print { + display: block; + float: right; + margin: 22px 0 0; + } + } } diff --git a/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less index a8d0bf8b584822f7e0084d690f9feb5ad04246a2..6596fe2fd79762908b1a87d2fbeac90fd8be7824 100644 --- a/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less @@ -158,11 +158,12 @@ .block-returns-tracking { .block-title { .action { - margin: 12px 0 0 30px; + margin: 0 0 0 30px; + } - &.track { - float: right; - } + .actions-track { + float: right; + margin-top: 12px; } } } diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less index f037c1c5777cbf8f761fddf779f7c8e9942278f8..a1109523d26b5ea6b85e794a66ebad3100a551c0 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less @@ -27,8 +27,7 @@ & when (@media-common = true) { - .checkout-index-index, - .checkout-onepage-success { + .checkout-index-index { .page-title-wrapper { &:extend(.abs-visually-hidden all); } @@ -66,6 +65,14 @@ margin-left: 0; } } + + .checkout-onepage-success { + &:extend(.abs-add-clearfix all); + + .print { + display: none; + } + } } // @@ -96,4 +103,12 @@ .lib-layout-column(2, 1, @checkout-wrapper__columns); padding-right: @indent__l; } + + .checkout-onepage-success { + .print { + display: block; + float: right; + margin: 23px 0 0; + } + } } diff --git a/app/design/frontend/Magento/luma/Magento_Rma/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Rma/web/css/source/_module.less index cfec28464244e59e48aeb16e674d8afcc33407b4..c7e955e69c3a66864e073365d2863968f014ed66 100644 --- a/app/design/frontend/Magento/luma/Magento_Rma/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Rma/web/css/source/_module.less @@ -176,11 +176,12 @@ .block-returns-tracking { .block-title { .action { - margin: 12px 0 0 30px; + margin: 0 0 0 30px; + } - &.track { - float: right; - } + .actions-track { + float: right; + margin-top: 12px; } } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Selection.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Selection.xml index 3a124f0cc38b5a76620fce7265890775a047d79f..e8485df0733de8385e31f55f2c95db9b0061848c 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Selection.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Selection.xml @@ -21,6 +21,10 @@ <selection_qty> <selector>[name$='[selection_qty]']</selector> </selection_qty> + <user_defined> + <selector>[name$='[selection_can_change_qty]']</selector> + <input>checkbox</input> + </user_defined> <getProductName> <selector>span[data-index="name"]</selector> </getProductName> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php index db349d16a86c673f7fcd89d57e94b42461f51012..ec96c5b27f50a39ffcfc6f88bfc5d1299a17af83 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php @@ -6,11 +6,10 @@ namespace Magento\Bundle\Test\Block\Catalog\Product; +use Magento\Bundle\Test\Block\Catalog\Product\View\Summary; use Magento\Bundle\Test\Block\Catalog\Product\View\Type\Bundle; -use Magento\Bundle\Test\Fixture\BundleProduct; use Magento\Mtf\Client\Locator; use Magento\Mtf\Fixture\FixtureInterface; -use Magento\Mtf\Fixture\InjectableFixture; /** * Class View @@ -46,6 +45,13 @@ class View extends \Magento\Catalog\Test\Block\Product\View */ protected $newsletterFormSelector = '#newsletter-validate-detail[novalidate="novalidate"]'; + /** + * Summary Block selector. + * + * @var string + */ + private $summaryBlockSelector = '#bundleSummary'; + /** * Get bundle options block. * @@ -59,6 +65,19 @@ class View extends \Magento\Catalog\Test\Block\Product\View ); } + /** + * Get bundle Summary block. + * + * @return Summary + */ + public function getBundleSummaryBlock() + { + return $this->blockFactory->create( + Summary::class, + ['element' => $this->_rootElement->find($this->summaryBlockSelector)] + ); + } + /** * Click "Customize and add to cart button". * diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary.php new file mode 100644 index 0000000000000000000000000000000000000000..76a46bfe3088a47f79dafa7f8c71d649e324b130 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Bundle\Test\Block\Catalog\Product\View; + +use Magento\Bundle\Test\Block\Catalog\Product\View\Summary\ConfiguredPrice; + +/** + * Bundle Summary block. + */ +class Summary extends \Magento\Catalog\Test\Block\Product\View +{ + /** + * Configured Price block selector. + * + * @var string + */ + private $configuredPriceBlockSelector = '.price-configured_price'; + + /** + * Get configured price block. + * + * @return ConfiguredPrice + */ + public function getConfiguredPriceBlock() + { + return $this->blockFactory->create( + ConfiguredPrice::class, + ['element' => $this->_rootElement->find($this->configuredPriceBlockSelector)] + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary/ConfiguredPrice.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary/ConfiguredPrice.php new file mode 100644 index 0000000000000000000000000000000000000000..30effcdeef060af5a81f92ed1a463e3f69bc57a0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary/ConfiguredPrice.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Bundle\Test\Block\Catalog\Product\View\Summary; + +/** + * This class is used to access the price related information from the storefront. + */ +class ConfiguredPrice extends \Magento\Catalog\Test\Block\AbstractPriceBlock +{ + /** + * Mapping for different type of price. + * + * @var array + */ + protected $mapTypePrices = [ + 'configured_price' => [ + 'selector' => '.price', + ] + ]; + + /** + * This method returns the price represented by the block. + * + * @param string $currency + * @return string|null + */ + public function getPrice($currency = '$') + { + return $this->getTypePrice('configured_price', $currency); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php index 23ac2d25ee017dab9e869e35b1dea7cac4abb94c..ccf47420b11521f9f5bf1a6c4b0f347d86c1baa0 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php @@ -107,11 +107,11 @@ class Bundle extends Block /** @var SimpleElement $optionElement */ $optionElement = $listFormOptions[$title]; - $getTypeData = 'get' . $this->optionNameConvert($option['type']) . 'Data'; + $getTypeData = 'get' . $this->optionNameConvert($option['frontend_type']) . 'Data'; $optionData = $this->$getTypeData($optionElement); $optionData['title'] = $title; - $optionData['type'] = $option['type']; + $optionData['type'] = $option['frontend_type']; $optionData['is_require'] = $optionElement->find($this->required, Locator::SELECTOR_XPATH)->isVisible() ? 'Yes' : 'No'; @@ -266,7 +266,7 @@ class Bundle extends Block /** @var Option $optionBlock */ $optionBlock = $this->blockFactory->create( 'Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option\\' - . $this->optionNameConvert($option['type']), + . $this->optionNameConvert($option['frontend_type']), ['element' => $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)] ); $optionBlock->fillOption($option['value']); diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Element/Qty.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Element/Qty.php new file mode 100644 index 0000000000000000000000000000000000000000..7506b81f8471c7ad8130aa45e31a1680cc26cd34 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Element/Qty.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option\Element; + +use Magento\Mtf\Client\Element\SimpleElement; + +/** + * Typified element class for qty element. + */ +class Qty extends SimpleElement +{ + /** + * "Backspace" key code. + */ + const BACKSPACE = "\xEE\x80\x83"; + + /** + * "RIGHT" key code. + */ + const RIGHT = "\xEE\x80\x94"; + + /** + * Set the value. + * + * @param string|array $value + * @return void + */ + public function setValue($value) + { + $this->keys([self::RIGHT, self::BACKSPACE, $value]); + $this->context->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.php new file mode 100644 index 0000000000000000000000000000000000000000..9fa54759b8e579728cdf2ea053d94481eb520503 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option; + +use Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option; + +/** + * Bundle option hidden type. + */ +class Hidden extends Option +{ + // +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.xml new file mode 100644 index 0000000000000000000000000000000000000000..356f6a52d6b0c296abc0eb857fe2d8b3dccc4b84 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<mapping strict="1"> + <fields> + <qty> + <selector>//input[contains(@class,"qty")]</selector> + <strategy>xpath</strategy> + <class>Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option\Element\Qty</class> + </qty> + </fields> +</mapping> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php index ddd8e35a301d6907cf75c3790cefaf6d79b394da..411c53d982fcb8a2445e8a5d214383670ec7bf4a 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php @@ -61,7 +61,7 @@ class AssertBundleItemsOnProductPage extends AbstractAssertForm foreach ($bundleOptions as $optionKey => $bundleOption) { $optionData = [ 'title' => $bundleOption['title'], - 'type' => $bundleOption['type'], + 'type' => $bundleOption['frontend_type'], 'is_require' => $bundleOption['required'], ]; diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php new file mode 100644 index 0000000000000000000000000000000000000000..756fe75eea7db1f943f3a8c490b8eb2427e63095 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Bundle\Test\Constraint; + +use Magento\Bundle\Test\Fixture\BundleProduct; +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Catalog\Test\TestStep\ConfigureProductOnProductPageStep; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\TestStep\TestStepFactory; + +/** + * Assert calculated price after configure bundle product on product page. + */ +class AssertBundlePriceCalculatedOnProductPage extends AbstractConstraint +{ + /** + * Assert calculated price after configure bundle product on product page. + * + * @param TestStepFactory $stepFactory + * @param BundleProduct $product + * @param CatalogProductView $catalogProductView + */ + public function processAssert( + TestStepFactory $stepFactory, + BundleProduct $product, + CatalogProductView $catalogProductView + ) { + $stepFactory->create(ConfigureProductOnProductPageStep::class, ['product' => $product])->run(); + + //Process assertions + $this->assertPrice($product, $catalogProductView); + } + + /** + * Assert prices on the product view Page. + * + * @param BundleProduct $product + * @param CatalogProductView $productView + * @return void + */ + protected function assertPrice(BundleProduct $product, CatalogProductView $productView) + { + $checkoutData = $product->getCheckoutData(); + \PHPUnit_Framework_Assert::assertEquals( + $checkoutData['cartItem']['configuredPrice'], + $productView->getBundleViewBlock()->getBundleSummaryBlock()->getConfiguredPriceBlock()->getPrice(), + 'Bundle price calculated is not correct.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Bundle price calculates right on product view page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php index 4a4aea603cf8619d0d12335f496b1e6a9e50fd33..6a3572ab15a7af1e9a84ee06841cedf772bc9283 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php @@ -68,6 +68,10 @@ class Curl extends ProductCurl implements BundleProductInterface 'gift_message_available' => [ 'Yes' => 1, 'No' => 0 + ], + 'user_defined' => [ + 'Yes' => 1, + 'No' => 0 ] ]; } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php index 634f6c00a6cc87aac749b187fafd2452e3fd98fb..2fbdaffefc7a33192c73309d0dde80729311b5d8 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php @@ -64,25 +64,8 @@ class Webapi extends SimpleProductWebapi implements BundleProductInterface 'title' => $bundleOption['title'], 'type' => $bundleOption['type'], 'required' => $bundleOption['required'], - 'product_links' => [], + 'product_links' => $this->prepareLinksInfo($bundleSelections, $key) ]; - - $productLinksInfo = $bundleOption['assigned_products']; - $products = $bundleSelections['products'][$key]; - foreach ($productLinksInfo as $linkKey => $productLink) { - $product = $products[$linkKey]; - $bundleProductOptions[$key]['product_links'][] = [ - 'sku' => $product->getSku(), - 'qty' => $productLink['data']['selection_qty'], - 'is_default' => false, - 'price' => isset($productLink['data']['selection_price_value']) - ? $productLink['data']['selection_price_value'] - : null, - 'price_type' => isset($productLink['data']['selection_price_type']) - ? $productLink['data']['selection_price_type'] - : null, - ]; - } } } @@ -92,6 +75,39 @@ class Webapi extends SimpleProductWebapi implements BundleProductInterface unset($this->fields['product']['bundle_selections']); } + /** + * Prepare links info field. + * + * @param array $bundleSelections + * @param int $key + * @return array + */ + private function prepareLinksInfo(array $bundleSelections, $key) + { + $result = []; + $productLinksInfo = $bundleSelections['bundle_options'][$key]['assigned_products']; + $products = $bundleSelections['products'][$key]; + foreach ($productLinksInfo as $linkKey => $productLink) { + $product = $products[$linkKey]; + $result[] = [ + 'sku' => $product->getSku(), + 'qty' => $productLink['data']['selection_qty'], + 'is_default' => false, + 'price' => isset($productLink['data']['selection_price_value']) + ? $productLink['data']['selection_price_value'] + : null, + 'price_type' => isset($productLink['data']['selection_price_type']) + ? $productLink['data']['selection_price_type'] + : null, + 'can_change_quantity' => isset($productLink['data']['user_defined']) + ? $productLink['data']['user_defined'] + : 0, + ]; + } + + return $result; + } + /** * Parse response. * diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml index 7131aab3cffcbb69ca84f1078540a2dbada2ae28..c19a78f64894e17b256a1ec13828b0612bdada08 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml @@ -12,6 +12,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -46,6 +47,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -84,6 +86,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -122,6 +125,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -160,6 +164,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -187,6 +192,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Radio Button Option</item> <item name="type" xsi:type="string">Radio Buttons</item> + <item name="frontend_type" xsi:type="string">Radio Buttons</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -214,6 +220,7 @@ <item name="2" xsi:type="array"> <item name="title" xsi:type="string">Checkbox Option</item> <item name="type" xsi:type="string">Checkbox</item> + <item name="frontend_type" xsi:type="string">Checkbox</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -241,6 +248,7 @@ <item name="3" xsi:type="array"> <item name="title" xsi:type="string">Multiple Select Option</item> <item name="type" xsi:type="string">Multiple Select</item> + <item name="frontend_type" xsi:type="string">Multiple Select</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -291,6 +299,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -314,6 +323,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Radio Button Option</item> <item name="type" xsi:type="string">Radio Buttons</item> + <item name="frontend_type" xsi:type="string">Radio Buttons</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -337,6 +347,7 @@ <item name="2" xsi:type="array"> <item name="title" xsi:type="string">Checkbox Option</item> <item name="type" xsi:type="string">Checkbox</item> + <item name="frontend_type" xsi:type="string">Checkbox</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -360,6 +371,7 @@ <item name="3" xsi:type="array"> <item name="title" xsi:type="string">Multiple Select Option</item> <item name="type" xsi:type="string">Multiple Select</item> + <item name="frontend_type" xsi:type="string">Multiple Select</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -406,6 +418,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">No</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -433,6 +446,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Radio Button Option</item> <item name="type" xsi:type="string">Radio Buttons</item> + <item name="frontend_type" xsi:type="string">Radio Buttons</item> <item name="required" xsi:type="string">No</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -475,6 +489,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -513,6 +528,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -547,6 +563,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -572,6 +589,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -610,6 +628,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -633,6 +652,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="required" xsi:type="string">Yes</item> <item name="assigned_products" xsi:type="array"> <item name="0" xsi:type="array"> @@ -830,5 +850,32 @@ </item> </field> </dataset> + + <dataset name="one_required_option_with_one_item"> + <field name="bundle_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Drop-down Option</item> + <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Hidden</item> + <item name="required" xsi:type="string">Yes</item> + <item name="assigned_products" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="search_data" xsi:type="array"> + <item name="name" xsi:type="string">%product_name%</item> + </item> + <item name="data" xsi:type="array"> + <item name="selection_qty" xsi:type="string">1</item> + <item name="user_defined" xsi:type="string">Yes</item> + </item> + </item> + </item> + </item> + </field> + <field name="products" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="0" xsi:type="string">catalogProductSimple::default</item> + </item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml index 3e7550b9d784e3858bd9800e66b88b8c60326b1b..d68fb0d0b83f8ff3520508a1c72bc51dcf8ff1c1 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml @@ -13,6 +13,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -27,6 +28,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -47,6 +49,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -67,6 +70,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_10_dollar</item> </item> @@ -87,6 +91,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">Simple Product</item> </item> @@ -107,6 +112,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -114,6 +120,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Radio Button Option</item> <item name="type" xsi:type="string">Radio Buttons</item> + <item name="frontend_type" xsi:type="string">Radio Buttons</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -128,6 +135,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -192,6 +200,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -212,6 +221,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_10_dollar</item> </item> @@ -242,6 +252,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -249,6 +260,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Radio Button Option</item> <item name="type" xsi:type="string">Radio Buttons</item> + <item name="frontend_type" xsi:type="string">Radio Buttons</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -256,6 +268,7 @@ <item name="2" xsi:type="array"> <item name="title" xsi:type="string">Checkbox Option</item> <item name="type" xsi:type="string">Checkbox</item> + <item name="frontend_type" xsi:type="string">Checkbox</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -263,6 +276,7 @@ <item name="3" xsi:type="array"> <item name="title" xsi:type="string">Multiple Select Option</item> <item name="type" xsi:type="string">Multiple</item> + <item name="frontend_type" xsi:type="string">Multiple</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -315,6 +329,7 @@ <item name="0" xsi:type="array"> <item name="title" xsi:type="string">Drop-down Option</item> <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Drop-down</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -322,6 +337,7 @@ <item name="1" xsi:type="array"> <item name="title" xsi:type="string">Radio Button Option</item> <item name="type" xsi:type="string">Radio Buttons</item> + <item name="frontend_type" xsi:type="string">Radio Buttons</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -329,6 +345,7 @@ <item name="2" xsi:type="array"> <item name="title" xsi:type="string">Checkbox Option</item> <item name="type" xsi:type="string">Checkbox</item> + <item name="frontend_type" xsi:type="string">Checkbox</item> <item name="value" xsi:type="array"> <item name="name" xsi:type="string">product_100_dollar</item> </item> @@ -357,5 +374,24 @@ </item> </field> </dataset> + + <dataset name="one_required_option_with_one_item"> + <field name="options" xsi:type="array"> + <item name="bundle_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Drop-down Option</item> + <item name="type" xsi:type="string">Drop-down</item> + <item name="frontend_type" xsi:type="string">Hidden</item> + <item name="value" xsi:type="array"> + <item name="name" xsi:type="string">Simple Product</item> + <item name="qty" xsi:type="string">3</item> + </item> + </item> + </item> + </field> + <field name="cartItem" xsi:type="array"> + <item name="configuredPrice" xsi:type="string">1680</item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml index 7d4ccea704ec7664c9c7da086c8367104b5fa677..56b2ceb917fe6d46296e408954bdfc88380af5a3 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml @@ -455,5 +455,17 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" /> </variation> + <variation name="CreateBundleProductEntityTestVariation25" summary="Create Bundle (dynamic) Product with one require option with one item" ticketId="MAGETWO-59841"> + <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data> + <data name="product/data/name" xsi:type="string">Bundle Dynamic %isolation%</data> + <data name="product/data/sku" xsi:type="string">sku_bundle_dynamic_%isolation%</data> + <data name="product/data/price_type" xsi:type="string">Yes</data> + <data name="product/data/category" xsi:type="string">category_%isolation%</data> + <data name="product/data/shipment_type" xsi:type="string">Together</data> + <data name="product/data/bundle_selections/dataset" xsi:type="string">one_required_option_with_one_item</data> + <data name="product/data/checkout_data/dataset" xsi:type="string">one_required_option_with_one_item</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> + <constraint name="Magento\Bundle\Test\Constraint\AssertBundlePriceCalculatedOnProductPage" /> + </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php index 3134fda0d2b2b3f98b3e9d0ef5c835e8cb1aad53..de6adb0efd8b21df23cf0531624fa0b90983225d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php @@ -10,7 +10,7 @@ use Magento\Catalog\Test\Block\AbstractConfigureBlock; use Magento\Catalog\Test\Fixture\CatalogProductSimple; use Magento\Mtf\Client\Locator; use Magento\Mtf\Fixture\FixtureInterface; -use Magento\Mtf\Fixture\InjectableFixture; +use Magento\Checkout\Test\Block\Cart\Sidebar; /** * Product view block on the product page. @@ -145,7 +145,14 @@ class View extends AbstractConfigureBlock * * @var string */ - protected $miniCartBlock = '[data-block="minicart"]'; + protected $miniCartBlockSelector = '[data-block="minicart"]'; + + /** + * Minicart block element. + * + * @var Sidebar + */ + private $miniCartBlock; /** * Success message selector. @@ -222,21 +229,44 @@ class View extends AbstractConfigureBlock */ public function addToCart(FixtureInterface $product) { - /** @var \Magento\Checkout\Test\Block\Cart\Sidebar $miniCart */ - $miniCart = $this->blockFactory->create( - \Magento\Checkout\Test\Block\Cart\Sidebar::class, - ['element' => $this->browser->find($this->miniCartBlock)] - ); + $this->configure($product); + $this->clickAddToCart(); + $this->getMiniCartBlock()->waitLoader(); + } + + /** + * Configure Product. + * + * @param FixtureInterface $product + * @return void + */ + public function configure(FixtureInterface $product) + { /** @var CatalogProductSimple $product */ $checkoutData = $product->getCheckoutData(); - $miniCart->waitInit(); + $this->getMiniCartBlock()->waitInit(); $this->fillOptions($product); if (isset($checkoutData['qty'])) { $this->setQty($checkoutData['qty']); } - $this->clickAddToCart(); - $miniCart->waitLoader(); + } + + /** + * Get MiniCart block. + * + * @return Sidebar + */ + private function getMiniCartBlock() + { + if ($this->miniCartBlock === null) { + $this->miniCartBlock = $this->blockFactory->create( + Sidebar::class, + ['element' => $this->browser->find($this->miniCartBlockSelector)] + ); + } + + return $this->miniCartBlock; } /** @@ -313,14 +343,8 @@ class View extends AbstractConfigureBlock public function braintreePaypalCheckout() { $currentWindow = $this->browser->getCurrentWindow(); - /** @var \Magento\Checkout\Test\Block\Cart\Sidebar $miniCart */ - $miniCart = $this->blockFactory->create( - \Magento\Checkout\Test\Block\Cart\Sidebar::class, - ['element' => $this->browser->find($this->miniCartBlock)] - ); - - $miniCart->openMiniCart(); - $miniCart->clickBraintreePaypalButton(); + $this->getMiniCartBlock()->openMiniCart(); + $this->getMiniCartBlock()->clickBraintreePaypalButton(); return $currentWindow; } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php index 54bf06f70b5f1c0f192b79bda3ade75a85cd37f7..da1ec8f71a1121bceba80b6a3138f77b07663310 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php @@ -13,9 +13,11 @@ use Magento\Mtf\Constraint\AbstractConstraint; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; +use Magento\Mtf\Client\BrowserInterface; /** * Check attribute on product form. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class AssertAddedProductAttributeOnProductForm extends AbstractConstraint { @@ -45,6 +47,13 @@ class AssertAddedProductAttributeOnProductForm extends AbstractConstraint */ protected $catalogProductEdit; + /** + * Locator for attributes section. + * + * @var string + */ + protected $attributes = '[data-index="attributes"]'; + /** * Add this attribute to Default attribute Template. Create product and Assert that created attribute * is displayed on product form (Products > Inventory > Catalog). @@ -66,6 +75,7 @@ class AssertAddedProductAttributeOnProductForm extends AbstractConstraint CatalogProductEdit $catalogProductEdit, CatalogProductAttribute $attribute, CatalogAttributeSet $attributeSet, + BrowserInterface $browser, CatalogProductAttribute $productAttributeOriginal = null ) { $this->fixtureFactory = $fixtureFactory; @@ -92,7 +102,9 @@ class AssertAddedProductAttributeOnProductForm extends AbstractConstraint $catalogProductAttribute = ($productAttributeOriginal !== null) ? array_merge($productAttributeOriginal->getData(), $attribute->getData()) : $attribute->getData(); - $catalogProductEdit->getProductForm()->openSection(self::ATTRIBUTES); + if ($browser->find($this->attributes)->isVisible()) { + $catalogProductEdit->getProductForm()->openSection(self::ATTRIBUTES); + } \PHPUnit_Framework_Assert::assertTrue( $catalogProductEdit->getProductForm()->checkAttributeLabel($catalogProductAttribute), diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php index a4a773ae7c7ecd02e11b6e824d6ec3d50925523b..db43cc535ca01c4bbac96e425a435bd71ef3fcef 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php @@ -47,6 +47,14 @@ class Curl extends AbstractCurl implements CatalogProductAttributeInterface 'No' => 0, 'Yes' => 1, ], + 'is_global' => [ + 'Store View' => '0', + 'Global' => '1', + ], + 'used_in_product_listing' => [ + 'No' => '0', + 'Yes' => '1', + ], ]; /** @@ -76,6 +84,7 @@ class Curl extends AbstractCurl implements CatalogProductAttributeInterface unset($data['options']); } + $data = $this->changeStructureOfTheData($data); $url = $_ENV['app_backend_url'] . 'catalog/product_attribute/save/back/edit'; $curl = new BackendDecorator(new CurlTransport(), $this->_configuration); $curl->write($url, $data); @@ -104,4 +113,13 @@ class Curl extends AbstractCurl implements CatalogProductAttributeInterface return $resultData; } + + /** + * @param array $data + * @return array + */ + protected function changeStructureOfTheData(array $data) + { + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/ConfigureProductOnProductPageStep.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/ConfigureProductOnProductPageStep.php new file mode 100644 index 0000000000000000000000000000000000000000..f2f08513d7297ad1a3fe3345c8bdca1b848e4819 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/ConfigureProductOnProductPageStep.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\TestStep; + +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Mtf\Client\BrowserInterface; +use Magento\Mtf\Fixture\InjectableFixture; +use Magento\Mtf\TestStep\TestStepInterface; + +/** + * Configure Product on Product Page step. + */ +class ConfigureProductOnProductPageStep implements TestStepInterface +{ + /** + * Product fixture. + * + * @var InjectableFixture + */ + private $product; + + /** + * Frontend product view page. + * + * @var CatalogProductView + */ + private $catalogProductView; + + /** + * Interface Browser. + * + * @var BrowserInterface + */ + private $browser; + + /** + * @constructor + * @param CatalogProductView $catalogProductView + * @param BrowserInterface $browser + * @param InjectableFixture $product + */ + public function __construct( + CatalogProductView $catalogProductView, + BrowserInterface $browser, + InjectableFixture $product + ) { + $this->product = $product; + $this->catalogProductView = $catalogProductView; + $this->browser = $browser; + } + + /** + * Configure product. + * + * @return void + */ + public function run() + { + $this->browser->open($_ENV['app_frontend_url'] . $this->product->getUrlKey() . '.html'); + $this->catalogProductView->getViewBlock()->configure($this->product); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php index cad6dda90459845718bc3ab1e3ac2952cca16640..ce8f5a4cbfd99b41e990a11fc89527f28b0fec5f 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php @@ -8,7 +8,6 @@ namespace Magento\Checkout\Test\Block\Onepage; use Magento\Mtf\Block\Block; use Magento\Mtf\Fixture\InjectableFixture; -use Magento\Payment\Test\Fixture\CreditCard; /** * Checkout payment block. @@ -90,7 +89,12 @@ class Payment extends Block } catch (\Exception $exception) { throw new \Exception('Such payment method is absent.'); } - + $browser = $this->browser; + $browser->waitUntil( + function () use ($browser, $paymentSelector) { + return $browser->find($paymentSelector); + } + ); $paymentRadioButton = $this->_rootElement->find($paymentSelector); if ($paymentRadioButton->isVisible()) { $paymentRadioButton->click(); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php new file mode 100644 index 0000000000000000000000000000000000000000..e5c3ab4dad9ee121c1332649dabd8715c3544449 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php @@ -0,0 +1,118 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\ConfigurableProduct\Test\Constraint; + +use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; +use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\Fixture\FixtureInterface; +use Magento\Mtf\ObjectManager; +use Magento\Mtf\System\Event\EventManagerInterface; +use Magento\Sales\Test\Fixture\OrderInjectable; + +/** + * Class AssertProductQtyDecreasedAfterCreditmemo + */ +class AssertProductQtyDecreasedAfterCreditmemo extends AbstractConstraint +{ + /** + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Skip fields for create product fixture. + * + * @var array + */ + protected $skipFields = [ + 'attribute_set_id', + 'website_ids', + 'checkout_data', + 'type_id', + 'price', + ]; + + /** + * AssertFirstProductForm constructor. + * @param ObjectManager $objectManager + */ + public function __construct( + ObjectManager $objectManager, + EventManagerInterface $eventManager, + FixtureFactory $fixtureFactory + ) { + $this->fixtureFactory = $fixtureFactory; + parent::__construct($objectManager, $eventManager); + } + + /** + * Assert form data equals fixture data + * + * @param OrderInjectable $order + * @param array $data + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $productPage + * @return void + */ + public function processAssert( + OrderInjectable $order, + array $data, + CatalogProductIndex $productGrid, + CatalogProductEdit $productPage + ) { + $product = $this->getProduct($order, $data); + $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert( + $product, + $productGrid, + $productPage + ); + } + + /** + * Get product's fixture. + * + * @param OrderInjectable $order + * @param array $data + * @param int $index [optional] + * @return FixtureInterface + */ + protected function getProduct(OrderInjectable $order, array $data, $index = 0) + { + if (!isset($data['items_data'][$index]['back_to_stock']) + || $data['items_data'][$index]['back_to_stock'] != 'Yes' + ) { + return $order->getEntityId()['products'][$index]; + } + $product = $order->getEntityId()['products'][$index]; + $productData = $product->getData(); + $checkoutDataQty = $productData['checkout_data']['qty']; + + $productKey = ''; + foreach ($productData['checkout_data']['options']['configurable_options'] as $option) { + $productKey .= ' ' . $option['title'] . ':' . $option['value']; + } + $productKey = trim($productKey); + $optionProduct = $productData['configurable_attributes_data']['matrix'][$productKey]; + $optionProduct['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']); + $productData = $optionProduct; + + $productData = array_diff_key($productData, array_flip($this->skipFields)); + + return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product qty was decreased after creditmemo creation.'; + } +} 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 bf5d5944aa3da0a7093d5bbe33ea00897f3b5397..626be7dee3652ee88407d47f1bac313a96dde225 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 @@ -172,7 +172,7 @@ class Curl extends ProductCurl implements ConfigurableProductInterface $keyIds[] = $attribute['options'][$optionKey]['id']; $configurableAttribute[] = sprintf( '"%s":"%s"', - $attribute['attribute_code'], + isset($attribute['attribute_code']) ? $attribute['attribute_code'] : $attribute['frontend_label'], $attribute['options'][$optionKey]['id'] ); } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml index 4a69a7604bca3d74119b07bdcea3b2115a1f6648..32f1957d4173f87b10069b60c8c428b921e260fb 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml @@ -71,7 +71,40 @@ </dataset> <dataset name="configurable_with_qty_1"> - <field name="name" xsi:type="string">Test configurable product %isolation%</field> + <field name="name" xsi:type="string">sku_test_configurable_product_%isolation%</field> + <field name="sku" xsi:type="string">sku_test_configurable_product_%isolation%</field> + <field name="price" xsi:type="array"> + <item name="dataset" xsi:type="string">price_40</item> + </field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">30</field> + <field name="status" xsi:type="string">Yes</field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="url_key" xsi:type="string">configurable-product-%isolation%</field> + <field name="configurable_attributes_data" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="checkout_data" xsi:type="array"> + <item name="dataset" xsi:type="string">configurable_options_with_qty_1</item> + </field> + </dataset> + + <dataset name="configurable_with_qty_2"> + <field name="name" xsi:type="string">sku_test_configurable_product_%isolation%</field> <field name="sku" xsi:type="string">sku_test_configurable_product_%isolation%</field> <field name="price" xsi:type="array"> <item name="dataset" xsi:type="string">price_40</item> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..dd92edc82b3310ad9610c70138578a220e4358cd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Sales\Test\TestCase\CreateCreditMemoEntityTest" summary="Create Credit Memo for Offline Payment Methods" ticketId="MAGETWO-59074"> + <variation name="CreateCreditMemoEntityWithConfigurableTestVariation1" ticketId="MAGETWO-12447"> + <data name="description" xsi:type="string">Assert items return to stock (partial refund)</data> + <data name="data/items_data/0/back_to_stock" xsi:type="string">Yes</data> + <data name="data/items_data/0/qty" xsi:type="string">1</data> + <data name="order/dataset" xsi:type="string">default</data> + <data name="order/data/entity_id/products" xsi:type="string">configurableProduct::configurable_with_qty_1</data> + <data name="order/data/price/dataset" xsi:type="string">full_refund</data> + <constraint name="Magento\Sales\Test\Constraint\AssertRefundSuccessCreateMessage" /> + <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertProductQtyDecreasedAfterCreditmemo" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php new file mode 100644 index 0000000000000000000000000000000000000000..f48e9e198210c02a66870674cbc35178b7d91df4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php @@ -0,0 +1,110 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Sales\Test\Constraint; + +use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; +use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\Fixture\FixtureInterface; +use Magento\Mtf\ObjectManager; +use Magento\Mtf\System\Event\EventManagerInterface; +use Magento\Sales\Test\Fixture\OrderInjectable; + +/** + * Class AssertProductQtyDecreasedAfterCreditmemo + */ +class AssertProductQtyDecreasedAfterCreditmemo extends AbstractConstraint +{ + /** + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Skip fields for create product fixture. + * + * @var array + */ + protected $skipFields = [ + 'attribute_set_id', + 'website_ids', + 'checkout_data', + 'type_id', + 'price', + ]; + + /** + * AssertFirstProductForm constructor. + * @param ObjectManager $objectManager + */ + public function __construct( + ObjectManager $objectManager, + EventManagerInterface $eventManager, + FixtureFactory $fixtureFactory + ) { + $this->fixtureFactory = $fixtureFactory; + parent::__construct($objectManager, $eventManager); + } + + /** + * Assert form data equals fixture data + * + * @param OrderInjectable $order + * @param array $data + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $productPage + * @return void + */ + public function processAssert( + OrderInjectable $order, + array $data, + CatalogProductIndex $productGrid, + CatalogProductEdit $productPage + ) { + $product = $this->getProduct($order, $data); + $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert( + $product, + $productGrid, + $productPage + ); + } + + /** + * Get product's fixture. + * + * @param OrderInjectable $order + * @param array $data + * @param int $index [optional] + * @return FixtureInterface + */ + protected function getProduct(OrderInjectable $order, array $data, $index = 0) + { + if (!isset($data['items_data'][$index]['back_to_stock']) + || $data['items_data'][$index]['back_to_stock'] != 'Yes' + ) { + return $order->getEntityId()['products'][$index]; + } + $product = $order->getEntityId()['products'][$index]; + $productData = $product->getData(); + $checkoutDataQty = $productData['checkout_data']['qty']; + $productData['quantity_and_stock_status']['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']); + + $productData = array_diff_key($productData, array_flip($this->skipFields)); + + return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product qty was decreased after creditmemo creation.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php index 9d19d10f4d40c6c3e317a97e7e83cd3c79e6f8ae..92b341bef2675fe635f804da2d9a17c5eea54c49 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php @@ -90,32 +90,7 @@ class CreateCreditMemoEntityTest extends Injectable return [ 'ids' => ['creditMemoIds' => $result['creditMemoIds']], - 'product' => $this->getProduct($order, $data), 'customer' => $order->getDataFieldConfig('customer_id')['source']->getCustomer() ]; } - - /** - * Get product's fixture. - * - * @param OrderInjectable $order - * @param array $data - * @param int $index [optional] - * @return FixtureInterface - */ - protected function getProduct(OrderInjectable $order, array $data, $index = 0) - { - if (!isset($data['items_data'][$index]['back_to_stock']) - || $data['items_data'][$index]['back_to_stock'] != 'Yes' - ) { - return $order->getEntityId()['products'][$index]; - } - $product = $order->getEntityId()['products'][$index]; - $productData = $product->getData(); - $checkoutDataQty = $productData['checkout_data']['qty']; - $productData['quantity_and_stock_status']['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']); - $productData = array_diff_key($productData, array_flip($this->skipFields)); - - return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); - } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml index 02b9640acbea4159c0560e8a4727a13cc36e1199..b2cf9843598f48af778edda5a4240409fd9d0365 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml @@ -22,7 +22,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertRefundOrderStatusInCommentsHistory" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderCommentsHistoryNotifyStatus" /> <constraint name="Magento\Sales\Test\Constraint\AssertRefundedGrandTotalOnFrontend" /> - <constraint name="Magento\Catalog\Test\Constraint\AssertProductForm" /> + <constraint name="Magento\Sales\Test\Constraint\AssertProductQtyDecreasedAfterCreditmemo" /> <constraint name="Magento\Sales\Test\Constraint\AssertCreditMemoItems" /> </variation> <variation name="CreateCreditMemoEntityTestVariation2" summary="Assert 0 shipping refund"> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php new file mode 100644 index 0000000000000000000000000000000000000000..39c630a0aa2060f23e6ef87c2682e73169ffa777 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Block\Product; + +use Magento\Mtf\Client\Locator; +use Magento\Mtf\Fixture\FixtureInterface; +use Magento\Catalog\Test\Block\Product\ListProduct as CatalogListProduct; + +/** + * Product list block. + */ +class ListProduct extends CatalogListProduct +{ + /** + * @inheritdoc + */ + public function getProductItem(FixtureInterface $product) + { + $locator = sprintf($this->productItem, $product->getName()); + + return $this->blockFactory->create( + \Magento\Swatches\Test\Block\Product\ProductList\ProductItem::class, + ['element' => $this->_rootElement->find($locator, Locator::SELECTOR_XPATH)] + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php new file mode 100755 index 0000000000000000000000000000000000000000..414d03bc687871490b551fcfb807f2958fd4e25e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Block\Product\ProductList; + +use Magento\Mtf\Client\Locator; +use Magento\Catalog\Test\Block\Product\ProductList\ProductItem as CatalogProductItem; + +/** + * Product item block on frontend category view. + */ +class ProductItem extends CatalogProductItem +{ + /** + * Selector for the swatches of the product. + * + * @var string + */ + protected $swatchSelector = 'div[option-id="%s"]'; + + /** + * Fill product options on category page. + * + * @param \Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct $product + * @return void + */ + public function fillData(\Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct $product) + { + $checkoutData = $product->getCheckoutData(); + $options = $checkoutData['options']['configurable_options']; + $confAttrData = $product->getDataFieldConfig('configurable_attributes_data'); + $confAttrSource = $confAttrData['source']; + $attributes = $confAttrSource->getAttributes(); + + foreach ($options as $option) { + if (!isset($attributes[$option['title']])) { + continue; + } + $availableOptions = $attributes[$option['title']]->getOptions(); + $optionKey = str_replace('option_key_', '', $option['value']); + if (!isset($availableOptions[$optionKey])) { + continue; + } + $optionForSelect = $availableOptions[$optionKey]; + $this->clickOnSwatch($optionForSelect['id']); + } + } + + /** + * Click on swatch. + * + * @param $optionId + */ + private function clickOnSwatch($optionId) + { + $selector = sprintf($this->swatchSelector, $optionId); + $this->_rootElement->find($selector, Locator::SELECTOR_CSS)->click(); + } + + /** + * @inheritdoc + */ + public function clickAddToCart() + { + $this->_rootElement->hover(); + parent::clickAddToCart(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php new file mode 100644 index 0000000000000000000000000000000000000000..c1405b4a807718edbb511569ac23d03fc2b52d43 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Block\Product; + +use Magento\Catalog\Test\Block\Product\View; +use Magento\Mtf\Fixture\InjectableFixture; + +/** + * Configurable product view block with swatch attributes on frontend product page + */ +class ViewWithSwatches extends View +{ + /** + * Selector for swatch attribute value + * + * @var string + */ + private $swatchAttributeSelector = '.swatch-attribute.%s .swatch-attribute-selected-option'; + + /** + * Get chosen options from the product view page. + * + * @param InjectableFixture $product + * @return array + */ + public function getSelectedSwatchOptions(InjectableFixture $product) + { + $checkoutData = $product->getCheckoutData(); + $availableAttributes = $product->getConfigurableAttributesData(); + $attributesData = $availableAttributes['attributes_data']; + $formData = []; + foreach ($checkoutData['options']['configurable_options'] as $item) { + $selector = sprintf($this->swatchAttributeSelector, $attributesData[$item['title']]['attribute_code']); + $this->waitForElementVisible($selector); + $selected = $this->_rootElement->find($selector)->getText(); + $formData[$item['title']] = $selected; + } + + return $formData; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchConfigurableProductPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchConfigurableProductPage.php new file mode 100644 index 0000000000000000000000000000000000000000..460a13ce49d704f30f513af5c8f3189c45f3ffc4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchConfigurableProductPage.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Constraint; + +use Magento\Catalog\Test\Constraint\AssertProductPage; +use Magento\Mtf\Fixture\FixtureInterface; +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Mtf\Client\BrowserInterface; + +/** + * Assert that product with swatches and regular dropdown redirect can't be add to cart from catalog catergory page. + */ +class AssertSwatchConfigurableProductPage extends AssertProductPage +{ + /** + * {@inheritdoc} + */ + public function processAssert( + BrowserInterface $browser, + CatalogProductView $catalogProductView, + FixtureInterface $product + ) { + $this->product = $product; + $this->productView = $catalogProductView->getProductViewWithSwatchesBlock(); + $this->objectManager->create( + \Magento\Swatches\Test\TestStep\AddProductToCartFromCatalogCategoryPageStep::class, + [ + 'product' => $product + ] + )->run(); + // we need this line for waiti until page will be fully loaded + $this->productView->getSelectedSwatchOptions($this->product); + $errors = $this->verify(); + \PHPUnit_Framework_Assert::assertEmpty( + $errors, + "\nFound the following errors:\n" . implode(" \n", $errors) + ); + } + + /** + * Verify product on product view page. + * + * @return array + */ + protected function verify() + { + $errors = parent::verify(); + $errors[] = $this->verifySwatches(); + + return array_filter($errors); + } + + /** + * Verify selected swatches on product view page. + * + * @return array + */ + protected function verifySwatches() + { + $actualData = $this->productView->getSelectedSwatchOptions($this->product); + $expectedData = $this->convertCheckoutData($this->product); + $this->verifyData($expectedData, $actualData); + } + + /** + * Get swatch attributes formatter to attributes comparison. + * + * @param FixtureInterface $product + * @return array + */ + public function convertCheckoutData(FixtureInterface $product) + { + $out = []; + $checkoutData = $product->getCheckoutData(); + $availableAttributes = $product->getConfigurableAttributesData(); + $attributesData = $availableAttributes['attributes_data']; + foreach ($checkoutData['options']['configurable_options'] as $item) { + $out[$item['title']] = $attributesData[$item['title']]['options'][$item['value']]['label']; + } + + return $out; + } + + /** + * Return string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Swatch attributes displayed as expected on product page'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/Cart/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..46c9b383ae8420c5210a3d4f71ac49b3513b1724 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/Cart/Item.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Fixture\Cart; + +use Magento\ConfigurableProduct\Test\Fixture\Cart\Item as ConfigurableCart; + +/** + * @inheritdoc + */ +class Item extends ConfigurableCart +{ + // +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/ConfigurableProduct.xml new file mode 100644 index 0000000000000000000000000000000000000000..dbc57a321a68238adff45355fd87a4e97028cde2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/ConfigurableProduct.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/fixture.xsd"> + <fixture + name="configurableProductSwatch" + module="Magento_Swatches" + class="Magento\Swatches\Test\Fixture\ConfigurableProduct" + extends="\Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct" + > + </fixture> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml new file mode 100644 index 0000000000000000000000000000000000000000..d96331b8159d50a60f6aa215d523d492aa5de7a4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/fixture.xsd"> + <fixture name="swatchesProductAttribute" + module="Magento_Swatches" + handler_interface="Magento\Swatches\Test\Handler\SwatchProductAttribute\SwatchProductAttributeInterface" + repository_class="Magento\Swatches\Test\Repository\SwatchProductAttribute" + class="Magento\Swatches\Test\Fixture\SwatchesProductAttribute" + extends="\Magento\Catalog\Test\Fixture\CatalogProductAttribute"> + </fixture> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php new file mode 100644 index 0000000000000000000000000000000000000000..86de2d651da1ecf3d48fdb165de0b223a665f126 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Handler\SwatchProductAttribute; + +use Magento\Catalog\Test\Handler\CatalogProductAttribute\Curl as CatalogProductAttributeCurl; +use Magento\Mtf\Config\DataInterface; +use Magento\Mtf\System\Event\EventManagerInterface; + +/** + * Curl handler for creating Swatch Attribute. + */ +class Curl extends CatalogProductAttributeCurl implements SwatchProductAttributeInterface +{ + /** + * Add mapping data related to swatches. + * + * @param DataInterface $configuration + * @param EventManagerInterface $eventManager + */ + public function __construct(DataInterface $configuration, EventManagerInterface $eventManager) + { + parent::__construct($configuration, $eventManager); + $this->mappingData['frontend_input'] = [ + 'Text Swatch' => 'swatch_text', + ]; + } + + /** + * Re-map options from default options structure to swatches structure, + * as swatches was initially created with name convention differ from other attributes. + * + * @param array $data + * @return array + */ + protected function changeStructureOfTheData(array $data) + { + $data = parent::changeStructureOfTheData($data); + $data['optiontext'] = $data['option']; + $data['swatchtext'] = [ + 'value' => $data['option']['value'] + ]; + unset($data['option']); + return $data; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..41fdebdd5ce8b084eca0a40c58aeba580a7b3518 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\Handler\SwatchProductAttribute; + +use Magento\Mtf\Handler\HandlerInterface; + +/** + * Interface for swatch specific Curl calls + */ +interface SwatchProductAttributeInterface extends HandlerInterface +{ + // +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Category/CatalogCategoryView.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Category/CatalogCategoryView.xml new file mode 100644 index 0000000000000000000000000000000000000000..9cb5e4fbdf69756a5289555e15d568f577bbf21d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Category/CatalogCategoryView.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd"> + <page name="CatalogCategoryView" area="Category" mca="catalog/category/view" module="Magento_Catalog"> + <block name="listSwatchesProductBlock" class="Magento\Swatches\Test\Block\Product\ListProduct" locator=".products.wrapper.grid" strategy="css selector"/> + </page> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Product/CatalogProductView.xml new file mode 100644 index 0000000000000000000000000000000000000000..315c6a02ee968e6bc93ec52bd5555d65be3f87d7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Product/CatalogProductView.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd"> + <page name="CatalogProductView" area="Product" mca="catalog/product/view"> + <block name="productViewWithSwatchesBlock" class="Magento\Swatches\Test\Block\Product\ViewWithSwatches" locator="#maincontent" strategy="css selector" /> + </page> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml new file mode 100644 index 0000000000000000000000000000000000000000..22e73572ead0d9081b3bdf15c78f75df12409a3c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\ConfigurableProduct\Test\Repository\ConfigurableProduct"> + <dataset name="product_with_text_swatch"> + <field name="name" xsi:type="string">Test configurable product with color and size %isolation%</field> + <field name="sku" xsi:type="string">sku_test_configurable_product_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">30</field> + <field name="status" xsi:type="string">Yes</field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="url_key" xsi:type="string">configurable-product-%isolation%</field> + <field name="configurable_attributes_data" xsi:type="array"> + <item name="dataset" xsi:type="string">text_swatch</item> + </field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="category_ids" xsi:type="array"> + <item name="dataset" xsi:type="string">default_subcategory</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">custom_attribute_set</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">40</item> + <item name="dataset" xsi:type="string">price_40</item> + </field> + <field name="checkout_data" xsi:type="array"> + <item name="dataset" xsi:type="string">two_text_swatches</item> + </field> + </dataset> + <dataset name="product_with_text_swatch_and_size"> + <field name="name" xsi:type="string">Test configurable product with color and size %isolation%</field> + <field name="sku" xsi:type="string">sku_test_configurable_product_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">30</field> + <field name="status" xsi:type="string">Yes</field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="url_key" xsi:type="string">configurable-product-%isolation%</field> + <field name="configurable_attributes_data" xsi:type="array"> + <item name="dataset" xsi:type="string">text_swatch_with_dropdown</item> + </field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="category_ids" xsi:type="array"> + <item name="dataset" xsi:type="string">default_subcategory</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">custom_attribute_set</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">40</item> + <item name="dataset" xsi:type="string">price_40</item> + </field> + <field name="checkout_data" xsi:type="array"> + <item name="dataset" xsi:type="string">swatches_with_dropdown</item> + </field> + </dataset> + </repository> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b369d5a536f0de9e41bb302910526dd8f5023fb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\ConfigurableProduct\Test\Repository\ConfigurableProduct\CheckoutData"> + <dataset name="two_text_swatches"> + <field name="options" xsi:type="array"> + <item name="configurable_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">attribute_key_0</item> + <item name="value" xsi:type="string">option_key_1</item> + </item> + <item name="1" xsi:type="array"> + <item name="title" xsi:type="string">attribute_key_1</item> + <item name="value" xsi:type="string">option_key_2</item> + </item> + </item> + </field> + <field name="qty" xsi:type="string">1</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">42</item> + <item name="qty" xsi:type="string">1</item> + <item name="subtotal" xsi:type="string">47</item> + </field> + </dataset> + <dataset name="swatches_with_dropdown"> + <field name="options" xsi:type="array"> + <item name="configurable_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">attribute_key_0</item> + <item name="value" xsi:type="string">option_key_1</item> + </item> + </item> + </field> + <field name="qty" xsi:type="string">1</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">42</item> + <item name="qty" xsi:type="string">1</item> + <item name="subtotal" xsi:type="string">47</item> + </field> + </dataset> + </repository> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml new file mode 100644 index 0000000000000000000000000000000000000000..492fda6b751c664bdfde231d813a866e24073f7b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\ConfigurableProduct\Test\Repository\ConfigurableProduct\ConfigurableAttributesData"> + <dataset name="text_swatch"> + <field name="attributes_data" xsi:type="array"> + <item name="attribute_key_0" xsi:type="array"> + <item name="options" xsi:type="array"> + <item name="option_key_0" xsi:type="array"> + <item name="pricing_value" xsi:type="string">12.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_1" xsi:type="array"> + <item name="pricing_value" xsi:type="string">20.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_2" xsi:type="array"> + <item name="pricing_value" xsi:type="string">18.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + </item> + </item> + <item name="attribute_key_1" xsi:type="array"> + <item name="options" xsi:type="array"> + <item name="option_key_0" xsi:type="array"> + <item name="pricing_value" xsi:type="string">42.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_1" xsi:type="array"> + <item name="pricing_value" xsi:type="string">40.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_2" xsi:type="array"> + <item name="pricing_value" xsi:type="string">48.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + </item> + </item> + </field> + <field name="attributes" xsi:type="array"> + <item name="attribute_key_0" xsi:type="string">swatchesProductAttribute::attribute_type_text_swatch</item> + <item name="attribute_key_1" xsi:type="string">swatchesProductAttribute::attribute_type_text_swatch</item> + </field> + <field name="matrix" xsi:type="array"> + <item name="attribute_key_0:option_key_0 attribute_key_1:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_0 attribute_key_1:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_0 attribute_key_1:option_key_2" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_1 attribute_key_1:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_1 attribute_key_1:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_1 attribute_key_1:option_key_2" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_2 attribute_key_1:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_2 attribute_key_1:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_2 attribute_key_1:option_key_2" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + </field> + </dataset> + <dataset name="text_swatch_with_dropdown"> + <field name="attributes_data" xsi:type="array"> + <item name="attribute_key_0" xsi:type="array"> + <item name="options" xsi:type="array"> + <item name="option_key_0" xsi:type="array"> + <item name="pricing_value" xsi:type="string">12.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_1" xsi:type="array"> + <item name="pricing_value" xsi:type="string">20.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_2" xsi:type="array"> + <item name="pricing_value" xsi:type="string">18.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + </item> + </item> + <item name="attribute_key_1" xsi:type="array"> + <item name="options" xsi:type="array"> + <item name="option_key_0" xsi:type="array"> + <item name="pricing_value" xsi:type="string">42.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_1" xsi:type="array"> + <item name="pricing_value" xsi:type="string">40.00</item> + <item name="include" xsi:type="string">Yes</item> + </item> + </item> + </item> + </field> + <field name="attributes" xsi:type="array"> + <item name="attribute_key_0" xsi:type="string">swatchesProductAttribute::attribute_type_text_swatch</item> + <item name="attribute_key_1" xsi:type="string">catalogProductAttribute::size</item> + </field> + <field name="matrix" xsi:type="array"> + <item name="attribute_key_0:option_key_0 attribute_key_1:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_0 attribute_key_1:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_1 attribute_key_1:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_1 attribute_key_1:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_2 attribute_key_1:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_2 attribute_key_1:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + </field> + </dataset> + </repository> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml new file mode 100644 index 0000000000000000000000000000000000000000..fc92146861d1e89e5ef32666c67b8c63882d9691 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\Swatches\Test\Repository\SwatchProductAttribute"> + <dataset name="attribute_type_text_swatch"> + <field name="attribute_code" xsi:type="string">sw_color%isolation%</field> + <field name="frontend_input" xsi:type="string" >Text Swatch</field> + <field name="frontend_label" xsi:type="string" >Text Swatch</field> + <field name="options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="is_default" xsi:type="string">No</item> + <item name="admin" xsi:type="string">R</item> + <item name="view" xsi:type="string">R</item> + </item> + <item name="1" xsi:type="array"> + <item name="is_default" xsi:type="string">No</item> + <item name="admin" xsi:type="string">G</item> + <item name="view" xsi:type="string">G</item> + </item> + <item name="2" xsi:type="array"> + <item name="is_default" xsi:type="string">No</item> + <item name="admin" xsi:type="string">B</item> + <item name="view" xsi:type="string">B</item> + </item> + </field> + <field name="is_global" xsi:type="string">Global</field> + <field name="used_in_product_listing" xsi:type="string">Yes</field> + </dataset> + </repository> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShopingCartTest.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShopingCartTest.php new file mode 100644 index 0000000000000000000000000000000000000000..60cc61f7f0f79319336d57d0d81289de6fe31cab --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShopingCartTest.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\TestCase; + +use Magento\Mtf\TestCase\Scenario; + +/** + * Preconditions: + * 1. Configure text swatch attribute. + * 2. Create configurable product with this attribute + * 3. Open it on catalog page + * 4. Click on 'Add to Cart' button + * + * Steps: + * 1. Go to Frontend. + * 2. Open category page with created product + * 3. Click on 'Add to Cart' button + * 4. Perform asserts + * + * @group Configurable_Product + * @ZephyrId MAGETWO-59958 + */ +class AddConfigurableProductWithSwatchToShopingCartTest extends Scenario +{ + /** + * Runs add configurable product with swatches attributes test. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShopingCartTest.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShopingCartTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..adf8d71395ccb9c4b714ad58887ec741391871a2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShopingCartTest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Swatches\Test\TestCase\AddConfigurableProductWithSwatchToShopingCartTest" summary="Create text swatch attribute" ticketId="MAGETWO-47017"> + <variation name="AddConfigurableProductWithSwatchToShopingCartTest1"> + <data name="attributeTypeAction" xsi:type="string">addOptions</data> + <data name="product" xsi:type="string">configurableProductSwatch::product_with_text_swatch</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertCartItemsOptions" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/TryToAddConfigurableProductWithSwatchToShopingCartTest.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/TryToAddConfigurableProductWithSwatchToShopingCartTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ac3016ade3f016b82a856677715db6c93736c1ef --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/TryToAddConfigurableProductWithSwatchToShopingCartTest.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\TestCase; + +use Magento\Mtf\TestCase\Scenario; + +/** + * Preconditions: + * 1. Configure text swatch attribute. + * 2. Create configurable product with this attribute + * 3. Open it on catalog page + * 4. Click on 'Add to Cart' button + * + * Steps: + * 1. Go to Frontend. + * 2. Open category page with created product + * 3. Click on 'Add to Cart' button + * 4. Perform asserts + * + * @group Configurable_Product + * @ZephyrId TODO: MAGETWO-59979 + */ +class TryToAddConfigurableProductWithSwatchToShopingCartTest extends Scenario +{ + /** + * Runs add configurable product with swatches attributes test. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/TryToAddConfigurableProductWithSwatchToShopingCartTest.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/TryToAddConfigurableProductWithSwatchToShopingCartTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..4cb7a3e01676f09c6c3e6b9ffcd3d85fb9abbe4a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/TryToAddConfigurableProductWithSwatchToShopingCartTest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Swatches\Test\TestCase\TryToAddConfigurableProductWithSwatchToShopingCartTest" summary="Create text swatch attribute" ticketId="MAGETWO-47017"> + <variation name="TryToAddConfigurableProductWithSwatchToShopingCartTest1"> + <data name="attributeTypeAction" xsi:type="string">addOptions</data> + <data name="product" xsi:type="string">configurableProductSwatch::product_with_text_swatch_and_size</data> + <constraint name="Magento\Swatches\Test\Constraint\AssertSwatchConfigurableProductPage" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php new file mode 100644 index 0000000000000000000000000000000000000000..e19f9d7b3c362ca61d5869ea409c20359b4b4ffb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php @@ -0,0 +1,96 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Swatches\Test\TestStep; + +use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Swatches\Test\Block\Product\ProductList\ProductItem; +use Magento\Mtf\Fixture\InjectableFixture; +use Magento\Catalog\Test\Page\Category\CatalogCategoryView; +use Magento\Cms\Test\Page\CmsIndex; + +/** + * Add configurable product to cart. + */ +class AddProductToCartFromCatalogCategoryPageStep implements TestStepInterface +{ + /** + * Fixture of configurable product with swatches configuration. + * + * @var \Magento\Swatches\Test\Fixture\ConfigurableProduct + */ + private $product; + + /** + * Fixture factory for create/get fixtures. + * + * @var FixtureFactory + */ + private $fixtureFactory; + + /** + * Page of catalog category view. + * + * @var CatalogCategoryView + */ + private $categoryView; + + /** + * CMS index page. + * + * @var CmsIndex + */ + private $cmsIndex; + + /** + * @constructor + * @param FixtureFactory $fixtureFactory + * @param CmsIndex $cmsIndex + * @param InjectableFixture $product + * @param CatalogCategoryView $categoryView + */ + public function __construct( + FixtureFactory $fixtureFactory, + CmsIndex $cmsIndex, + CatalogCategoryView $categoryView, + InjectableFixture $product + ) { + $this->fixtureFactory = $fixtureFactory; + $this->cmsIndex = $cmsIndex; + $this->categoryView = $categoryView; + $this->product = $product; + } + + /** + * Update configurable product. + * + * @return array + */ + public function run() + { + $categoryName = $this->product->getCategoryIds()[0]; + $this->cmsIndex->open(); + $this->cmsIndex->getTopmenu()->selectCategoryByName($categoryName); + /** @var \Magento\Swatches\Test\Block\Product\ListProduct $productsList */ + $productsList = $this->categoryView->getListSwatchesProductBlock(); + /** @var ProductItem $productItemBlock */ + $productItemBlock = $productsList->getProductItem($this->product); + $productItemBlock->fillData($this->product); + $productItemBlock->clickAddToCart(); + $cart = [ + 'data' => [ + 'items' => [ + 'products' => [$this->product] + ] + ] + ]; + + return [ + 'cart' => $this->fixtureFactory->createByCode('cart', $cart) + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac3ad40f804e1abac634c135228d89fca3a90876 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <preference for="Magento\Swatches\Test\Handler\SwatchProductAttribute\SwatchProductAttributeInterface" type="\Magento\Swatches\Test\Handler\SwatchProductAttribute\Curl" /> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/testcase.xml new file mode 100644 index 0000000000000000000000000000000000000000..f2e30c42a7a859e52ad129eda213aa8b1e597aad --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/testcase.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/TestCase/etc/testcase.xsd"> + <scenario name="AddConfigurableProductWithSwatchToShopingCartTest" firstStep="createProduct"> + <step name="createProduct" module="Magento_Catalog" next="addProductToCartFromCatalogCategoryPage" /> + <step name="addProductToCartFromCatalogCategoryPage" module="Magento_Swatches" /> + </scenario> + <scenario name="TryToAddConfigurableProductWithSwatchToShopingCartTest" firstStep="createProduct"> + <step name="createProduct" module="Magento_Catalog" /> + </scenario> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/Curl/RemoveTaxRule.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/Curl/RemoveTaxRule.php index 31ca2396f07827735fa3f686facb412807bdf59e..3e69145b42b3416efb88b6557c780d83eae59a1c 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/Curl/RemoveTaxRule.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/Curl/RemoveTaxRule.php @@ -39,9 +39,9 @@ class RemoveTaxRule extends Curl public function persist(FixtureInterface $fixture = null) { $this->taxRuleGridUrl = $_ENV['app_backend_url'] . 'tax/rule/index/'; - $curl = $this->_getCurl($this->taxRuleGridUrl); + $curl = $this->getCurl($this->taxRuleGridUrl); $response = $curl->read(); - $this->_removeTaxRules($response); + $this->removeTaxRules($response); $curl->close(); return $response; } diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php index 50a5657a4783088eabef74ea56aed23cd8592835..2a03872f4be6bce82a7764ec0358f83c654a5b0a 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php @@ -7,12 +7,20 @@ namespace Magento\Widget\Test\Block\Adminhtml\Widget; use Magento\Backend\Test\Block\Widget\Grid as AbstractGrid; +use Magento\Mtf\Client\Locator; /** * Widget grid on the Widget Instance Index page. */ class WidgetGrid extends AbstractGrid { + /** + * Selector for not empty options at select element. + * + * @var string + */ + private $notEmptyOptionsSelector = 'option:not([value=""])'; + /** * Locator value for link in action column. * @@ -36,5 +44,28 @@ class WidgetGrid extends AbstractGrid 'title' => [ 'selector' => 'input[name="title"]', ], + 'theme_id' => [ + 'selector' => 'select[name="theme_id"]', + 'input' => 'select', + ], ]; + + /** + * Returns values of theme_id filter. + * + * @return array + */ + public function getThemeIdValues() + { + $values = []; + $themeFilter = $this->filters['theme_id']; + $strategy = empty($themeFilter['strategy']) ? Locator::SELECTOR_CSS : $themeFilter['strategy']; + $element = $this->_rootElement->find($themeFilter['selector'], $strategy, $themeFilter['input']); + $options = $element->getElements($this->notEmptyOptionsSelector); + foreach ($options as $option) { + $values[] = $option->getText(); + } + + return $values; + } } diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php new file mode 100644 index 0000000000000000000000000000000000000000..31ebfd87c252b6e4142263636eb00329ab8d72b7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Widget\Test\Constraint; + +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Widget\Test\Fixture\Widget; +use Magento\Widget\Test\Page\Adminhtml\WidgetInstanceIndex; + +/** + * Assert theme filter contains all possible values from created widgets. + */ +class AssertThemeFilterValuesOnWidgetGrid extends AbstractConstraint +{ + /** + * Assert theme filter contains all possible values from created widgets. + * + * @param Widget[] $widgets + * @param WidgetInstanceIndex $widgetInstanceIndex + * @return void + */ + public function processAssert(array $widgets, WidgetInstanceIndex $widgetInstanceIndex) + { + $expectedValues = []; + foreach ($widgets as $widget) { + $expectedValues[] = $widget->getThemeId(); + } + $widgetInstanceIndex->open(); + $actualValues = $widgetInstanceIndex->getWidgetGrid()->getThemeIdValues(); + \PHPUnit_Framework_Assert::assertEmpty( + array_diff($expectedValues, $actualValues), + 'Widget grid theme filter doesn\'t contain all possible values from created widgets.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Widget grid theme filter contains all possible values from created widgets.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php index 5382d544a94b9f590a3475c915025c205e1453cd..2cc675f79fbd38a0f7654b40acc5d215be2a5191 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php @@ -11,7 +11,7 @@ use Magento\Widget\Test\Page\Adminhtml\WidgetInstanceIndex; use Magento\Mtf\Constraint\AbstractConstraint; /** - * Class AssertWidgetInGrid + * Assert widget is present in widget grid. */ class AssertWidgetInGrid extends AbstractConstraint { @@ -20,7 +20,10 @@ class AssertWidgetInGrid extends AbstractConstraint /* end tags */ /** - * Assert widget availability in widget grid + * Assert widget availability in widget grid. + * Verifying such fields as: + * - title + * - theme_id * * @param Widget $widget * @param WidgetInstanceIndex $widgetInstanceIndex @@ -28,7 +31,7 @@ class AssertWidgetInGrid extends AbstractConstraint */ public function processAssert(Widget $widget, WidgetInstanceIndex $widgetInstanceIndex) { - $filter = ['title' => $widget->getTitle()]; + $filter = ['title' => $widget->getTitle(), 'theme_id' => $widget->getThemeId()]; $widgetInstanceIndex->open(); \PHPUnit_Framework_Assert::assertTrue( $widgetInstanceIndex->getWidgetGrid()->isRowVisible($filter), @@ -37,7 +40,7 @@ class AssertWidgetInGrid extends AbstractConstraint } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetsInGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetsInGrid.php new file mode 100644 index 0000000000000000000000000000000000000000..bc61b3ef66f51585b0e21fc7dc1a64b7f04e57f7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetsInGrid.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Widget\Test\Constraint; + +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Widget\Test\Fixture\Widget; +use Magento\Widget\Test\Page\Adminhtml\WidgetInstanceIndex; + +/** + * Assert widgets are present in widget grid. + */ +class AssertWidgetsInGrid extends AbstractConstraint +{ + /** + * Assert widgets are present in widget grid. + * Verifying such fields as: + * - title + * - theme_id + * + * @param Widget[] $widgets + * @param WidgetInstanceIndex $widgetInstanceIndex + * @param AssertWidgetInGrid $assertWidgetInGrid + * @return void + */ + public function processAssert( + array $widgets, + WidgetInstanceIndex $widgetInstanceIndex, + AssertWidgetInGrid $assertWidgetInGrid + ) { + foreach ($widgets as $widget) { + $assertWidgetInGrid->processAssert($widget, $widgetInstanceIndex); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Widgets are present in widget grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/Curl.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/Curl.php index 4c9e61cdb873db0b32d3b77d9c16be3601537364..54520d0786a52732123a7fc0634d363f74d4b43d 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/Curl.php @@ -27,6 +27,7 @@ class Curl extends AbstractCurl protected $mappingData = [ 'code' => [ 'CMS Page Link' => 'cms_page_link', + 'Recently Viewed Products' => 'recently_viewed', ], 'block' => [ 'Main Content Area' => 'content', diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml index dc39ed7fa1259a02da5eadbc84c38e22f64c71aa..4a8972bfd8dbb3f5a80b7f6fc8a7e20c2f80e0fc 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml @@ -25,5 +25,20 @@ <item name="dataset" xsi:type="string">cmsPageLink</item> </field> </dataset> + + <dataset name="recently_viewed_products_on_blank_theme"> + <field name="code" xsi:type="string">Recently Viewed Products</field> + <field name="title" xsi:type="string">Title_%isolation%</field> + <field name="theme_id" xsi:type="string">Magento Blank</field> + <field name="store_ids" xsi:type="array"> + <item name="dataset" xsi:type="string">all_store_views</item> + </field> + <field name="widget_instance" xsi:type="array"> + <item name="dataset" xsi:type="string">for_viewed_products</item> + </field> + <field name="parameters" xsi:type="array"> + <item name="dataset" xsi:type="string">recentlyViewedProducts</item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php index 6358ac8821f26b621de3e83f7ef8380ffb7c3efc..cc02293ff8fdd98febf581beb87e8a00d7b128fb 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php @@ -48,7 +48,7 @@ class CreateWidgetEntityTest extends AbstractCreateWidgetEntityTest // Preconditions $this->caches = $caches; $this->adjustCacheSettings(); - + // Steps $this->widgetInstanceIndex->open(); $this->widgetInstanceIndex->getPageActionsBlock()->addNew(); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5269c315f78fc23c55e6848ec2482f850cdf2c0e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Widget\Test\TestCase; + +use Magento\Mtf\Fixture\FixtureFactory; +use \Magento\Mtf\TestCase\Injectable; +use Magento\Widget\Test\Fixture\Widget; + +/** + * Steps: + * 1. Create widgets. + * 2. Perform all assertions. + * + * @group Widget + * @ZephyrId MAGETWO-60672 + */ +class CreateWidgetsEntityTest extends Injectable +{ + /* tags */ + const SEVERITY = 'S3'; + /* end tags */ + + /** + * Create multiple widgets. + * + * @param array $widgets + * @param FixtureFactory $fixtureFactory + * @return array + */ + public function test(array $widgets, FixtureFactory $fixtureFactory) + { + /** @var Widget[] $widgetInstances */ + $widgetInstances = []; + // Preconditions + foreach ($widgets as $widget) { + $widget = $fixtureFactory->createByCode('widget', ['dataset' => $widget]); + $widget->persist(); + $widgetInstances[] = $widget; + } + + return ['widgets' => $widgetInstances]; + } + + /** + * Delete all widgets. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create(\Magento\Widget\Test\TestStep\DeleteAllWidgetsStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..484ea26cf5253a6524b77e299ccdc2532924d3e9 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Widget\Test\TestCase\CreateWidgetsEntityTest" summary="Create Widget" ticketId="MAGETWO-60672"> + <variation name="CreateWidgetEntityTestWithDifferentThemes" summary="Widgets with different themes is presented in grid/filter"> + <data name="tag" xsi:type="string">severity:S3</data> + <data name="widgets/0" xsi:type="string">default</data> + <data name="widgets/1" xsi:type="string">recently_viewed_products_on_blank_theme</data> + <constraint name="Magento\Widget\Test\Constraint\AssertThemeFilterValuesOnWidgetGrid" /> + <constraint name="Magento\Widget\Test\Constraint\AssertWidgetsInGrid" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml index 122a9659cf2b6be0706218e1f761870784179ea7..c1595838b4f63d51d1732857c7ccdd6d6ff8bec3 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml @@ -66,4 +66,14 @@ <argument name="severity" xsi:type="string">S1</argument> </arguments> </type> + <type name="Magento\Widget\Test\Constraint\AssertWidgetsInGrid"> + <arguments> + <argument name="severity" xsi:type="string">S3</argument> + </arguments> + </type> + <type name="Magento\Widget\Test\Constraint\AssertThemeFilterValuesOnWidgetGrid"> + <arguments> + <argument name="severity" xsi:type="string">S3</argument> + </arguments> + </type> </config> diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Controller/Cart/Index/CouponPostTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Controller/Cart/Index/CouponPostTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a6031429c66023491e2c411748046e76ecbddf41 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Checkout/Controller/Cart/Index/CouponPostTest.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Controller\Cart\Index; + +/** + * @magentoDbIsolation enabled + */ +class CouponPostTest extends \Magento\TestFramework\TestCase\AbstractController +{ + /** + * Test for \Magento\Checkout\Controller\Cart\CouponPost::execute() with simple product + * + * @magentoDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php + */ + public function testExecute() + { + /** @var $session \Magento\Checkout\Model\Session */ + $session = $this->_objectManager->create(\Magento\Checkout\Model\Session::class); + $quote = $session->getQuote(); + $quote->setData('trigger_recollect', 1)->setTotalsCollectedFlag(true); + $inputData = [ + 'remove' => 0, + 'coupon_code' => 'test' + ]; + $this->getRequest()->setPostValue($inputData); + $this->dispatch( + 'checkout/cart/couponPost/' + ); + + $this->assertSessionMessages( + $this->equalTo(['The coupon code "test" is not valid.']), + \Magento\Framework\Message\MessageInterface::TYPE_ERROR + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeManagementTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..82d83938db148ace03cedf19a89cf098517a1d56 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeManagementTest.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Eav\Model; + +class AttributeManagementTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Eav\Api\AttributeManagementInterface + */ + private $model; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->create(\Magento\Eav\Api\AttributeManagementInterface::class); + } + + /** + * Verify that collection in service used correctly + */ + public function testGetList() + { + $productAttributeSetId = $this->getAttributeSetId( + \Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE + ); + $productAttributes = $this->model->getAttributes( + \Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE, + $productAttributeSetId + ); + // Verify that result contains only product attributes + $this->verifyAttributeSetIds($productAttributes, $productAttributeSetId); + + $categoryAttributeSetId = $this->getAttributeSetId( + \Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE + ); + $categoryAttributes = $this->model->getAttributes( + \Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE, + $categoryAttributeSetId + ); + // Verify that result contains only category attributes + $this->verifyAttributeSetIds($categoryAttributes, $categoryAttributeSetId); + } + + /** + * @param string $entityTypeCode + * @return int + */ + private function getAttributeSetId($entityTypeCode) + { + /** @var \Magento\Eav\Model\Config $eavConfig */ + $eavConfig = $this->objectManager->create(\Magento\Eav\Model\Config::class); + return $eavConfig->getEntityType($entityTypeCode)->getDefaultAttributeSetId(); + } + + /** + * @param array $items + * @param string $attributeSetId + * @return void + */ + private function verifyAttributeSetIds(array $items, $attributeSetId) + { + /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $item */ + foreach ($items as $item) { + $this->assertEquals($attributeSetId, $item->getAttributeSetId()); + } + } +}