diff --git a/app/code/Magento/Catalog/Pricing/Price/MinimalPriceCalculatorInterface.php b/app/code/Magento/Catalog/Pricing/Price/MinimalPriceCalculatorInterface.php new file mode 100644 index 0000000000000..de31b1d5b51a9 --- /dev/null +++ b/app/code/Magento/Catalog/Pricing/Price/MinimalPriceCalculatorInterface.php @@ -0,0 +1,32 @@ +calculator = $calculator; + } + + /** + * Get raw value of "as low as" as a minimal among tier prices. + * + * @param SaleableInterface $saleableItem + * @return float|null + */ + public function getValue(SaleableInterface $saleableItem) + { + /** @var TierPrice $price */ + $price = $saleableItem->getPriceInfo()->getPrice(TierPrice::PRICE_CODE); + $tierPriceList = $price->getTierPriceList(); + + $tierPrices = []; + foreach ($tierPriceList as $tierPrice) { + /** @var AmountInterface $price */ + $price = $tierPrice['price']; + $tierPrices[] = $price->getValue(); + } + + return $tierPrices ? min($tierPrices) : null; + } + + /** + * Return calculated amount object that keeps "as low as" value. + * + * @param SaleableInterface $saleableItem + * @return AmountInterface|null + */ + public function getAmount(SaleableInterface $saleableItem) + { + $value = $this->getValue($saleableItem); + + return $value === null ? null : $this->calculator->getAmount($value, $saleableItem); + } +} diff --git a/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php b/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php index bab93e08f2753..afe3e0f7374a7 100644 --- a/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php +++ b/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php @@ -8,40 +8,49 @@ use Magento\Catalog\Pricing\Price; use Magento\Framework\App\ObjectManager; -use Magento\Framework\Module\Manager; -use Magento\Framework\Pricing\Render; use Magento\Framework\Pricing\Render\PriceBox as BasePriceBox; -use Magento\Msrp\Pricing\Price\MsrpPrice; -use Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface; -use Magento\Framework\View\Element\Template\Context; use Magento\Framework\Pricing\SaleableInterface; use Magento\Framework\Pricing\Price\PriceInterface; use Magento\Framework\Pricing\Render\RendererPool; +use Magento\Msrp\Pricing\Price\MsrpPrice; +use Magento\Framework\View\Element\Template\Context; /** - * Class for final_price rendering + * Class for final_price rendering. * * @method bool getUseLinkForAsLowAs() * @method bool getDisplayMinimalPrice() - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class FinalPriceBox extends BasePriceBox { /** - * @var SalableResolverInterface + * Interface resolver provided to check is product available for sale. + * + * @var \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface */ private $salableResolver; - /** @var Manager */ + /** + * Module statuses manager. + * + * @var \Magento\Framework\Module\Manager + */ private $moduleManager; + /** + * Shows minimal value of Tier Prices. + * + * @var \Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface + */ + private $minimalPriceCalculator; + /** * @param Context $context * @param SaleableInterface $saleableItem * @param PriceInterface $price * @param RendererPool $rendererPool * @param array $data - * @param SalableResolverInterface $salableResolver + * @param \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface $salableResolver */ public function __construct( Context $context, @@ -49,11 +58,11 @@ public function __construct( PriceInterface $price, RendererPool $rendererPool, array $data = [], - SalableResolverInterface $salableResolver = null + \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface $salableResolver = null ) { parent::__construct($context, $saleableItem, $price, $rendererPool, $data); - $this->salableResolver = $salableResolver ?: \Magento\Framework\App\ObjectManager::getInstance() - ->get(SalableResolverInterface::class); + $this->salableResolver = $salableResolver ?: ObjectManager::getInstance() + ->get(\Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface::class); } /** @@ -116,7 +125,7 @@ private function isMsrpPriceApplicable() } /** - * Wrap with standard required container + * Wrap with standard required container. * * @param string $html * @return string @@ -130,17 +139,21 @@ protected function wrapResult($html) } /** - * Render minimal amount + * Render minimal amount. * * @return string */ public function renderAmountMinimal() { - /** @var \Magento\Catalog\Pricing\Price\FinalPrice $price */ - $price = $this->getPriceType(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE); $id = $this->getPriceId() ? $this->getPriceId() : 'product-minimal-price-' . $this->getSaleableItem()->getId(); + $amount = $this->getMinimalPriceCalculator()->getAmount($this->getSaleableItem()); + + if ($amount === null) { + return ''; + } + return $this->renderAmount( - $price->getMinimalPrice(), + $amount, [ 'display_label' => __('As low as'), 'price_id' => $id, @@ -151,7 +164,7 @@ public function renderAmountMinimal() } /** - * Define if the special price should be shown + * Define if the special price should be shown. * * @return bool */ @@ -163,23 +176,25 @@ public function hasSpecialPrice() } /** - * Define if the minimal price should be shown + * Define if the minimal price should be shown. * * @return bool */ public function showMinimalPrice() { + $minTierPrice = $this->getMinimalPriceCalculator()->getValue($this->getSaleableItem()); + /** @var Price\FinalPrice $finalPrice */ $finalPrice = $this->getPriceType(Price\FinalPrice::PRICE_CODE); $finalPriceValue = $finalPrice->getAmount()->getValue(); - $minimalPriceAValue = $finalPrice->getMinimalPrice()->getValue(); + return $this->getDisplayMinimalPrice() - && $minimalPriceAValue - && $minimalPriceAValue < $finalPriceValue; + && $minTierPrice !== null + && $minTierPrice < $finalPriceValue; } /** - * Get Key for caching block content + * Get Key for caching block content. * * @return string */ @@ -203,19 +218,19 @@ public function getCacheKeyInfo() /** * @deprecated - * @return Manager + * @return \Magento\Framework\Module\Manager */ private function getModuleManager() { if ($this->moduleManager === null) { - $this->moduleManager = ObjectManager::getInstance()->get(Manager::class); + $this->moduleManager = ObjectManager::getInstance()->get(\Magento\Framework\Module\Manager::class); } return $this->moduleManager; } /** - * Get flag that price rendering should be done for the list of products - * By default (if flag is not set) is false + * Get flag that price rendering should be done for the list of products. + * By default (if flag is not set) is false. * * @return bool */ @@ -224,4 +239,18 @@ public function isProductList() $isProductList = $this->getData('is_product_list'); return $isProductList === true; } + + /** + * @deprecated + * @return \Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface + */ + private function getMinimalPriceCalculator() + { + if ($this->minimalPriceCalculator == null) { + $this->minimalPriceCalculator = ObjectManager::getInstance() + ->get(\Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface::class); + } + + return $this->minimalPriceCalculator; + } } diff --git a/app/code/Magento/Catalog/Setup/UpgradeData.php b/app/code/Magento/Catalog/Setup/UpgradeData.php index 9961441cd5bda..b3a30d8fa21da 100644 --- a/app/code/Magento/Catalog/Setup/UpgradeData.php +++ b/app/code/Magento/Catalog/Setup/UpgradeData.php @@ -5,13 +5,10 @@ */ namespace Magento\Catalog\Setup; -use Magento\Catalog\Api\Data\ProductAttributeInterface; -use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; use Magento\Framework\Setup\UpgradeDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Eav\Setup\EavSetup; -use Magento\Eav\Setup\EavSetupFactory; /** * Upgrade Data script @@ -29,20 +26,32 @@ class UpgradeData implements UpgradeDataInterface /** * EAV setup factory * - * @var EavSetupFactory + * @var \Magento\Eav\Setup\EavSetupFactory */ private $eavSetupFactory; + /** + * Attributes cache management. + * + * @var \Magento\Eav\Model\Entity\AttributeCache + */ + private $attributeCache; + /** * Init * * @param CategorySetupFactory $categorySetupFactory - * @param EavSetupFactory $eavSetupFactory + * @param \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory + * @param \Magento\Eav\Model\Entity\AttributeCache $attributeCache */ - public function __construct(CategorySetupFactory $categorySetupFactory, EavSetupFactory $eavSetupFactory) - { + public function __construct( + CategorySetupFactory $categorySetupFactory, + \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory, + \Magento\Eav\Model\Entity\AttributeCache $attributeCache + ) { $this->categorySetupFactory = $categorySetupFactory; $this->eavSetupFactory = $eavSetupFactory; + $this->attributeCache = $attributeCache; } /** @@ -87,7 +96,7 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface if (version_compare($context->getVersion(), '2.0.2') < 0) { // set new resource model paths - /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + /** @var CategorySetup $categorySetup */ $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); $categorySetup->updateEntityType( \Magento\Catalog\Model\Category::ENTITY, @@ -128,69 +137,75 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface } if (version_compare($context->getVersion(), '2.0.3') < 0) { - /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + /** @var CategorySetup $categorySetup */ $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); $categorySetup->updateAttribute(3, 54, 'default_value', 1); } if (version_compare($context->getVersion(), '2.0.4') < 0) { - /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + $mediaBackendType = 'static'; + $mediaBackendModel = null; + /** @var CategorySetup $categorySetup */ $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); $categorySetup->updateAttribute( 'catalog_product', 'media_gallery', 'backend_type', - 'static' + $mediaBackendType ); $categorySetup->updateAttribute( 'catalog_product', 'media_gallery', - 'backend_model' + 'backend_model', + $mediaBackendModel ); + + $this->changeMediaGalleryAttributeInCache($mediaBackendType, $mediaBackendModel); } if (version_compare($context->getVersion(), '2.0.5', '<')) { - /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + /** @var CategorySetup $categorySetup */ $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); //Product Details tab $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'status', 'frontend_label', 'Enable Product', 5 ); $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'name', 'frontend_label', 'Product Name' ); + $attributeSetId = $categorySetup->getDefaultAttributeSetId(\Magento\Catalog\Model\Product::ENTITY); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Product Details', 'visibility', 80 ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Product Details', 'news_from_date', 90 ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Product Details', 'news_to_date', 100 ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Product Details', 'country_of_manufacture', 110 @@ -198,27 +213,27 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface //Content tab $categorySetup->addAttributeGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Content', 15 ); $categorySetup->updateAttributeGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Content', 'tab_group_code', 'basic' ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Content', 'description' ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Content', 'short_description', 100 @@ -226,39 +241,39 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface //Images tab $groupId = (int)$categorySetup->getAttributeGroupByCode( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'image-management', 'attribute_group_id' ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, $groupId, 'image', 1 ); $categorySetup->updateAttributeGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, $groupId, 'attribute_group_name', 'Images' ); $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'image', 'frontend_label', 'Base' ); $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'small_image', 'frontend_label', 'Small' ); $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'image', 'frontend_input_renderer', null @@ -266,13 +281,13 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface //Design tab $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'page_layout', 'frontend_label', 'Layout' ); $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'custom_layout_update', 'frontend_label', 'Layout Update XML', @@ -281,56 +296,56 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface //Schedule Design Update tab $categorySetup->addAttributeGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Schedule Design Update', 55 ); $categorySetup->updateAttributeGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Schedule Design Update', 'tab_group_code', 'advanced' ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Schedule Design Update', 'custom_design_from', 20 ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Schedule Design Update', 'custom_design_to', 30 ); $categorySetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'custom_design', 'frontend_label', 'New Theme', 40 ); $categorySetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'Default', + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, 'Schedule Design Update', 'custom_design' ); $categorySetup->addAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'custom_layout', [ 'type' => 'varchar', 'label' => 'New Layout', 'input' => 'select', - 'source' => 'Magento\Catalog\Model\Product\Attribute\Source\Layout', + 'source' => \Magento\Catalog\Model\Product\Attribute\Source\Layout::class, 'required' => false, 'sort_order' => 50, - 'global' => ScopedAttributeInterface::SCOPE_STORE, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Schedule Design Update', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -338,13 +353,13 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface ] ); } - + if (version_compare($context->getVersion(), '2.0.7') < 0) { /** @var EavSetup $eavSetup */ - $eavSetup= $this->eavSetupFactory->create(['setup' => $setup]); + $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, + \Magento\Catalog\Model\Product::ENTITY, 'meta_description', [ 'note' => 'Maximum 255 chars. Meta Description should optimally be between 150-160 characters' @@ -353,7 +368,7 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface } if (version_compare($context->getVersion(), '2.1.3') < 0) { - /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + /** @var CategorySetup $categorySetup */ $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); $this->changePriceAttributeDefaultScope($categorySetup); } @@ -362,7 +377,7 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface } /** - * @param \Magento\Catalog\Setup\CategorySetup $categorySetup + * @param CategorySetup $categorySetup * @return void */ private function changePriceAttributeDefaultScope($categorySetup) @@ -379,4 +394,30 @@ private function changePriceAttributeDefaultScope($categorySetup) } } + + /** + * Change media_gallery attribute metadata in cache. + * + * @param string $mediaBackendType + * @param string $mediaBackendModel + * @return void + */ + private function changeMediaGalleryAttributeInCache($mediaBackendType, $mediaBackendModel) + { + // need to do, because media_gallery has backend model in cache. + $catalogProductAttributes = $this->attributeCache->getAttributes( + \Magento\Catalog\Model\Product::ENTITY, + '0-0' + ); + + if (is_array($catalogProductAttributes)) { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $catalogProductAttribute */ + foreach ($catalogProductAttributes as $catalogProductAttribute) { + if ($catalogProductAttribute->getAttributeCode() == 'media_gallery') { + $catalogProductAttribute->setBackendModel($mediaBackendModel); + $catalogProductAttribute->setBackendType($mediaBackendType); + } + } + } + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/MinimalTierPriceCalculatorTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/MinimalTierPriceCalculatorTest.php new file mode 100644 index 0000000000000..a649d3500c965 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/MinimalTierPriceCalculatorTest.php @@ -0,0 +1,112 @@ +price = $this->getMock(TierPrice::class, [], [], '', false); + $this->priceInfo = $this->getMockForAbstractClass(PriceInfoInterface::class); + $this->saleable = $this->getMockForAbstractClass(SaleableInterface::class); + + $this->objectManager = new ObjectManager($this); + + $this->calculator = $this->getMockForAbstractClass(CalculatorInterface::class); + $this->object = $this->objectManager->getObject( + MinimalTierPriceCalculator::class, + ['calculator' => $this->calculator] + ); + } + + private function getValueTierPricesExistShouldReturnMinTierPrice() + { + $minPrice = 5; + $notMinPrice = 10; + + $minAmount = $this->getMockForAbstractClass(AmountInterface::class); + $minAmount->expects($this->once())->method('getValue')->willReturn($minPrice); + + $notMinAmount = $this->getMockForAbstractClass(AmountInterface::class); + $notMinAmount->expects($this->once())->method('getValue')->willReturn($notMinPrice); + $tierPriceList = [ + [ + 'price' => $minAmount + ], + [ + 'price' => $notMinAmount + ] + ]; + + $this->price->expects($this->once())->method('getTierPriceList')->willReturn($tierPriceList); + + $this->priceInfo->expects($this->once())->method('getPrice')->with(TierPrice::PRICE_CODE) + ->willReturn($this->price); + + $this->saleable->expects($this->once())->method('getPriceInfo')->willReturn($this->priceInfo); + + return $minPrice; + } + + public function testGetValueTierPricesExistShouldReturnMinTierPrice() + { + $minPrice = $this->getValueTierPricesExistShouldReturnMinTierPrice(); + $this->assertEquals($minPrice, $this->object->getValue($this->saleable)); + } + + public function testGetGetAmountMinTierPriceExistShouldReturnAmountObject() + { + $minPrice = $this->getValueTierPricesExistShouldReturnMinTierPrice(); + + $amount = $this->getMockForAbstractClass(AmountInterface::class); + + $this->calculator->expects($this->once()) + ->method('getAmount') + ->with($minPrice, $this->saleable) + ->willReturn($amount); + + $this->assertSame($amount, $this->object->getAmount($this->saleable)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php index f2455661cf2d6..0b1690c8f73f1 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php @@ -9,6 +9,10 @@ use Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface; use Magento\Framework\Module\Manager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface; +use Magento\Framework\Pricing\Amount\AmountInterface; +use Magento\Framework\Pricing\Render\Amount; +use Magento\Catalog\Pricing\Price\FinalPrice; /** * Class FinalPriceBoxTest @@ -72,6 +76,11 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ private $moduleManager; + /** + * @var MinimalPriceCalculatorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $minimalPriceCalculator; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -168,7 +177,7 @@ protected function setUp() $this->price = $this->getMock(\Magento\Framework\Pricing\Price\PriceInterface::class); $this->price->expects($this->any()) ->method('getPriceCode') - ->will($this->returnValue(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE)); + ->will($this->returnValue(FinalPrice::PRICE_CODE)); $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -176,6 +185,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMockForAbstractClass(); + $this->minimalPriceCalculator =$this->getMockBuilder(MinimalPriceCalculatorInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->object = $this->objectManager->getObject( \Magento\Catalog\Pricing\Render\FinalPriceBox::class, [ @@ -184,7 +197,8 @@ protected function setUp() 'rendererPool' => $this->rendererPool, 'price' => $this->price, 'data' => ['zone' => 'test_zone', 'list_category_page' => true], - 'salableResolver' => $this->salableResolverMock + 'salableResolver' => $this->salableResolverMock, + 'minimalPriceCalculator' => $this->minimalPriceCalculator ] ); @@ -316,12 +330,18 @@ public function testRenderMsrpNotRegisteredException() public function testRenderAmountMinimal() { - $priceType = $this->getMock(\Magento\Catalog\Pricing\Price\FinalPrice::class, [], [], '', false); - $amount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); $priceId = 'price_id'; $html = 'html'; $this->object->setData('price_id', $priceId); + $this->product->expects($this->never())->method('getId'); + + $amount = $this->getMockForAbstractClass(AmountInterface::class); + + $this->minimalPriceCalculator->expects($this->once())->method('getAmount') + ->with($this->product) + ->willReturn($amount); + $arguments = [ 'zone' => 'test_zone', 'list_category_page' => true, @@ -331,24 +351,15 @@ public function testRenderAmountMinimal() 'skip_adjustments' => true, ]; - $amountRender = $this->getMock(\Magento\Framework\Pricing\Render\Amount::class, ['toHtml'], [], '', false); + $amountRender = $this->getMock(Amount::class, ['toHtml'], [], '', false); $amountRender->expects($this->once()) ->method('toHtml') - ->will($this->returnValue($html)); - - $this->priceInfo->expects($this->once()) - ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) - ->will($this->returnValue($priceType)); - - $priceType->expects($this->once()) - ->method('getMinimalPrice') - ->will($this->returnValue($amount)); + ->willReturn($html); $this->rendererPool->expects($this->once()) ->method('createAmountRender') ->with($amount, $this->product, $this->price, $arguments) - ->will($this->returnValue($amountRender)); + ->willReturn($amountRender); $this->assertEquals($html, $this->object->renderAmountMinimal()); } @@ -362,9 +373,9 @@ public function testRenderAmountMinimal() public function testHasSpecialPrice($regularPrice, $finalPrice, $expectedResult) { $regularPriceType = $this->getMock(\Magento\Catalog\Pricing\Price\RegularPrice::class, [], [], '', false); - $finalPriceType = $this->getMock(\Magento\Catalog\Pricing\Price\FinalPrice::class, [], [], '', false); - $regularPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); - $finalPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $finalPriceType = $this->getMock(FinalPrice::class, [], [], '', false); + $regularPriceAmount = $this->getMockForAbstractClass(AmountInterface::class); + $finalPriceAmount = $this->getMockForAbstractClass(AmountInterface::class); $regularPriceAmount->expects($this->once()) ->method('getValue') @@ -386,7 +397,7 @@ public function testHasSpecialPrice($regularPrice, $finalPrice, $expectedResult) ->will($this->returnValue($regularPriceType)); $this->priceInfo->expects($this->at(1)) ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) + ->with(FinalPrice::PRICE_CODE) ->will($this->returnValue($finalPriceType)); $this->assertEquals($expectedResult, $this->object->hasSpecialPrice()); @@ -403,35 +414,30 @@ public function hasSpecialPriceProvider() public function testShowMinimalPrice() { - $finalPrice = 10.0; $minimalPrice = 5.0; - $displayMininmalPrice = 2.0; - - $this->object->setDisplayMinimalPrice($displayMininmalPrice); + $finalPrice = 10.0; + $displayMininmalPrice = true; - $finalPriceType = $this->getMock(\Magento\Catalog\Pricing\Price\FinalPrice::class, [], [], '', false); + $this->minimalPriceCalculator->expects($this->once())->method('getValue')->with($this->product) + ->willReturn($minimalPrice); - $finalPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); - $minimalPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $finalPriceAmount = $this->getMockForAbstractClass(AmountInterface::class); $finalPriceAmount->expects($this->once()) ->method('getValue') ->will($this->returnValue($finalPrice)); - $minimalPriceAmount->expects($this->once()) - ->method('getValue') - ->will($this->returnValue($minimalPrice)); - $finalPriceType->expects($this->at(0)) + $finalPriceType = $this->getMock(FinalPrice::class, [], [], '', false); + $finalPriceType->expects($this->once()) ->method('getAmount') ->will($this->returnValue($finalPriceAmount)); - $finalPriceType->expects($this->at(1)) - ->method('getMinimalPrice') - ->will($this->returnValue($minimalPriceAmount)); $this->priceInfo->expects($this->once()) ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) - ->will($this->returnValue($finalPriceType)); + ->with(FinalPrice::PRICE_CODE) + ->willReturn($finalPriceType); + + $this->object->setDisplayMinimalPrice($displayMininmalPrice); $this->assertTrue($this->object->showMinimalPrice()); } diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index ae1bc9c524c8e..44a65b6697d0c 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -807,4 +807,5 @@ + diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index cbcbbd66897b1..ac5fe77c2498f 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1249,7 +1249,7 @@ protected function _saveProductAttributes(array $attributesData) $linkId = $this->_connection->fetchOne( $this->_connection->select() ->from($this->getResource()->getTable('catalog_product_entity')) - ->where('sku = ?', $sku) + ->where('sku = ?', (string)$sku) ->columns($this->getProductEntityLinkField()) ); diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index 206ad612900a9..93892eb8156d8 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -47,7 +47,8 @@ public function execute(\Magento\Framework\Event\Observer $observer) { /** @var Category $category */ $category = $observer->getEvent()->getCategory(); - if ($category->getUrlKey() !== false) { + $useDefaultAttribute = !$category->isObjectNew() && !empty($category->getData('use_default')['url_key']); + if ($category->getUrlKey() !== false && !$useDefaultAttribute) { $category->setUrlKey($this->categoryUrlPathGenerator->getUrlKey($category)) ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); if (!$category->isObjectNew()) { diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php index a6fdc41cd11ee..db153f6cb0a4a 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php @@ -37,16 +37,34 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa protected function setUp() { $this->observer = $this->getMock( - 'Magento\Framework\Event\Observer', - ['getEvent', 'getCategory'], + \Magento\Framework\Event\Observer::class, + [ + 'getEvent', + 'getCategory' + ], + [], + '', + false + ); + $this->categoryResource = $this->getMock( + \Magento\Catalog\Model\ResourceModel\Category::class, + [], [], '', false ); - $this->categoryResource = $this->getMock('Magento\Catalog\Model\ResourceModel\Category', [], [], '', false); $this->category = $this->getMock( - 'Magento\Catalog\Model\Category', - ['setUrlKey', 'setUrlPath', 'dataHasChangedFor', 'isObjectNew', 'getResource', 'getUrlKey', 'getStoreId'], + \Magento\Catalog\Model\Category::class, + [ + 'setUrlKey', + 'setUrlPath', + 'dataHasChangedFor', + 'isObjectNew', + 'getResource', + 'getUrlKey', + 'getStoreId', + 'getData' + ], [], '', false @@ -55,18 +73,18 @@ protected function setUp() $this->observer->expects($this->any())->method('getEvent')->willReturnSelf(); $this->observer->expects($this->any())->method('getCategory')->willReturn($this->category); $this->categoryUrlPathGenerator = $this->getMock( - 'Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator', + \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator::class, [], [], '', false ); $this->childrenCategoriesProvider = $this->getMock( - 'Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider' + \Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider::class ); $this->storeViewService = $this->getMock( - 'Magento\CatalogUrlRewrite\Service\V1\StoreViewService', + \Magento\CatalogUrlRewrite\Service\V1\StoreViewService::class, [], [], '', @@ -74,7 +92,7 @@ protected function setUp() ); $this->categoryUrlPathAutogeneratorObserver = (new ObjectManagerHelper($this))->getObject( - 'Magento\CatalogUrlRewrite\Observer\CategoryUrlPathAutogeneratorObserver', + \Magento\CatalogUrlRewrite\Observer\CategoryUrlPathAutogeneratorObserver::class, [ 'categoryUrlPathGenerator' => $this->categoryUrlPathGenerator, 'childrenCategoriesProvider' => $this->childrenCategoriesProvider, @@ -90,7 +108,7 @@ public function testSetCategoryUrlAndCategoryPath() $this->category->expects($this->once())->method('setUrlKey')->with('urk_key')->willReturnSelf(); $this->categoryUrlPathGenerator->expects($this->once())->method('getUrlPath')->willReturn('url_path'); $this->category->expects($this->once())->method('setUrlPath')->with('url_path')->willReturnSelf(); - $this->category->expects($this->once())->method('isObjectNew')->willReturn(true); + $this->category->expects($this->exactly(2))->method('isObjectNew')->willReturn(true); $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); } @@ -114,7 +132,7 @@ public function testUrlKeyAndUrlPathUpdating() $this->category->expects($this->once())->method('setUrlKey')->with('url_key')->willReturnSelf(); $this->category->expects($this->once())->method('setUrlPath')->with('url_path')->willReturnSelf(); // break code execution - $this->category->expects($this->once())->method('isObjectNew')->willReturn(true); + $this->category->expects($this->exactly(2))->method('isObjectNew')->willReturn(true); $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); } @@ -128,7 +146,7 @@ public function testUrlPathAttributeNoUpdatingIfCategoryIsNew() $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); - $this->category->expects($this->once())->method('isObjectNew')->willReturn(true); + $this->category->expects($this->exactly(2))->method('isObjectNew')->willReturn(true); $this->categoryResource->expects($this->never())->method('saveAttribute'); $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); @@ -142,7 +160,7 @@ public function testUrlPathAttributeUpdating() $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); - $this->category->expects($this->once())->method('isObjectNew')->willReturn(false); + $this->category->expects($this->exactly(2))->method('isObjectNew')->willReturn(false); $this->categoryResource->expects($this->once())->method('saveAttribute')->with($this->category, 'url_path'); @@ -162,7 +180,7 @@ public function testChildrenUrlPathAttributeNoUpdatingIfParentUrlPathIsNotChange $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); - $this->category->expects($this->once())->method('isObjectNew')->willReturn(false); + $this->category->expects($this->exactly(2))->method('isObjectNew')->willReturn(false); // break code execution $this->category->expects($this->once())->method('dataHasChangedFor')->with('url_path')->willReturn(false); @@ -177,7 +195,7 @@ public function testChildrenUrlPathAttributeUpdatingForSpecificStore() $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); - $this->category->expects($this->any())->method('isObjectNew')->willReturn(false); + $this->category->expects($this->exactly(2))->method('isObjectNew')->willReturn(false); $this->category->expects($this->any())->method('dataHasChangedFor')->willReturn(true); // only for specific store $this->category->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php index 61f423f77cee8..006fce54465ac 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php @@ -9,6 +9,10 @@ use Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface; use Magento\Framework\Module\Manager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface; +use Magento\Framework\Pricing\Amount\AmountInterface; +use Magento\Framework\Pricing\Render\Amount; +use Magento\Catalog\Pricing\Price\FinalPrice; /** * Class FinalPriceBoxTest @@ -72,6 +76,11 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ private $moduleManager; + /** + * @var MinimalPriceCalculatorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $minimalPriceCalculator; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -89,12 +98,12 @@ protected function setUp() ->method('getPriceInfo') ->will($this->returnValue($this->priceInfo)); - $eventManager = $this->getMock('Magento\Framework\Event\Test\Unit\ManagerStub', [], [], '', false); + $eventManager = $this->getMock(\Magento\Framework\Event\Test\Unit\ManagerStub::class, [], [], '', false); $config = $this->getMock('Magento\Store\Model\Store\Config', [], [], '', false); - $this->layout = $this->getMock('Magento\Framework\View\Layout', [], [], '', false); + $this->layout = $this->getMock(\Magento\Framework\View\Layout::class, [], [], '', false); - $this->priceBox = $this->getMock('Magento\Framework\Pricing\Render\PriceBox', [], [], '', false); - $this->logger = $this->getMock('Psr\Log\LoggerInterface'); + $this->priceBox = $this->getMock(\Magento\Framework\Pricing\Render\PriceBox::class, [], [], '', false); + $this->logger = $this->getMock(\Psr\Log\LoggerInterface::class); $this->layout->expects($this->any())->method('getBlock')->willReturn($this->priceBox); @@ -117,8 +126,8 @@ protected function setUp() ->getMockForAbstractClass(); $storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store)); - $scopeConfigMock = $this->getMockForAbstractClass('Magento\Framework\App\Config\ScopeConfigInterface'); - $context = $this->getMock('Magento\Framework\View\Element\Template\Context', [], [], '', false); + $scopeConfigMock = $this->getMockForAbstractClass(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $context = $this->getMock(\Magento\Framework\View\Element\Template\Context::class, [], [], '', false); $context->expects($this->any()) ->method('getEventManager') ->will($this->returnValue($eventManager)); @@ -150,11 +159,11 @@ protected function setUp() ->method('getUrlBuilder') ->will($this->returnValue($urlBuilder)); - $this->rendererPool = $this->getMockBuilder('Magento\Framework\Pricing\Render\RendererPool') + $this->rendererPool = $this->getMockBuilder(\Magento\Framework\Pricing\Render\RendererPool::class) ->disableOriginalConstructor() ->getMock(); - $this->price = $this->getMock('Magento\Framework\Pricing\Price\PriceInterface'); + $this->price = $this->getMock(\Magento\Framework\Pricing\Price\PriceInterface::class); $this->price->expects($this->any()) ->method('getPriceCode') ->will($this->returnValue(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE)); @@ -165,15 +174,18 @@ protected function setUp() ->disableOriginalConstructor() ->getMockForAbstractClass(); + $this->minimalPriceCalculator = $this->getMockForAbstractClass(MinimalPriceCalculatorInterface::class); + $this->object = $this->objectManager->getObject( - 'Magento\Catalog\Pricing\Render\FinalPriceBox', + \Magento\Catalog\Pricing\Render\FinalPriceBox::class, [ 'context' => $context, 'saleableItem' => $this->product, 'rendererPool' => $this->rendererPool, 'price' => $this->price, 'data' => ['zone' => 'test_zone', 'list_category_page' => true], - 'salableResolver' => $this->salableResolverMock + 'salableResolver' => $this->salableResolverMock, + 'minimalPriceCalculator' => $this->minimalPriceCalculator ] ); @@ -191,7 +203,7 @@ protected function setUp() public function testRenderMsrpDisabled() { - $priceType = $this->getMock('Magento\Msrp\Pricing\Price\MsrpPrice', [], [], '', false); + $priceType = $this->getMock(\Magento\Msrp\Pricing\Price\MsrpPrice::class, [], [], '', false); $this->moduleManager->expects(self::once()) ->method('isEnabled') @@ -223,7 +235,7 @@ public function testRenderMsrpDisabled() public function testRenderMsrpEnabled() { - $priceType = $this->getMock('Magento\Msrp\Pricing\Price\MsrpPrice', [], [], '', false); + $priceType = $this->getMock(\Magento\Msrp\Pricing\Price\MsrpPrice::class, [], [], '', false); $this->moduleManager->expects(self::once()) ->method('isEnabled') @@ -250,7 +262,7 @@ public function testRenderMsrpEnabled() ->with($this->equalTo($this->product)) ->will($this->returnValue(true)); - $priceBoxRender = $this->getMockBuilder('Magento\Framework\Pricing\Render\PriceBox') + $priceBoxRender = $this->getMockBuilder(\Magento\Framework\Pricing\Render\PriceBox::class) ->disableOriginalConstructor() ->getMock(); $priceBoxRender->expects($this->once()) @@ -305,12 +317,19 @@ public function testRenderMsrpNotRegisteredException() public function testRenderAmountMinimal() { - $priceType = $this->getMock('Magento\Catalog\Pricing\Price\FinalPrice', [], [], '', false); - $amount = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface'); $priceId = 'price_id'; $html = 'html'; + $this->object->setData('price_id', $priceId); + $this->product->expects($this->never())->method('getId'); + + $amount = $this->getMockForAbstractClass(AmountInterface::class); + + $this->minimalPriceCalculator->expects($this->once())->method('getAmount') + ->with($this->product) + ->willReturn($amount); + $arguments = [ 'zone' => 'test_zone', 'list_category_page' => true, @@ -320,24 +339,15 @@ public function testRenderAmountMinimal() 'skip_adjustments' => true, ]; - $amountRender = $this->getMock('Magento\Framework\Pricing\Render\Amount', ['toHtml'], [], '', false); + $amountRender = $this->getMock(Amount::class, ['toHtml'], [], '', false); $amountRender->expects($this->once()) ->method('toHtml') - ->will($this->returnValue($html)); - - $this->priceInfo->expects($this->once()) - ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) - ->will($this->returnValue($priceType)); - - $priceType->expects($this->once()) - ->method('getMinimalPrice') - ->will($this->returnValue($amount)); + ->willReturn($html); $this->rendererPool->expects($this->once()) ->method('createAmountRender') ->with($amount, $this->product, $this->price, $arguments) - ->will($this->returnValue($amountRender)); + ->willReturn($amountRender); $this->assertEquals($html, $this->object->renderAmountMinimal()); } @@ -350,10 +360,10 @@ public function testRenderAmountMinimal() */ public function testHasSpecialPrice($regularPrice, $finalPrice, $expectedResult) { - $regularPriceType = $this->getMock('Magento\Catalog\Pricing\Price\RegularPrice', [], [], '', false); - $finalPriceType = $this->getMock('Magento\Catalog\Pricing\Price\FinalPrice', [], [], '', false); - $regularPriceAmount = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface'); - $finalPriceAmount = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface'); + $regularPriceType = $this->getMock(\Magento\Catalog\Pricing\Price\RegularPrice::class, [], [], '', false); + $finalPriceType = $this->getMock(\Magento\Catalog\Pricing\Price\FinalPrice::class, [], [], '', false); + $regularPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $finalPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); $regularPriceAmount->expects($this->once()) ->method('getValue') @@ -392,35 +402,31 @@ public function hasSpecialPriceProvider() public function testShowMinimalPrice() { - $finalPrice = 10.0; $minimalPrice = 5.0; - $displayMininmalPrice = 2.0; - - $this->object->setDisplayMinimalPrice($displayMininmalPrice); + $finalPrice = 10.0; + $displayMininmalPrice = true; - $finalPriceType = $this->getMock('Magento\Catalog\Pricing\Price\FinalPrice', [], [], '', false); + $this->minimalPriceCalculator->expects($this->once())->method('getValue')->with($this->product) + ->willReturn($minimalPrice); - $finalPriceAmount = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface'); - $minimalPriceAmount = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface'); + $finalPriceAmount = $this->getMockForAbstractClass(AmountInterface::class); $finalPriceAmount->expects($this->once()) ->method('getValue') ->will($this->returnValue($finalPrice)); - $minimalPriceAmount->expects($this->once()) - ->method('getValue') - ->will($this->returnValue($minimalPrice)); - $finalPriceType->expects($this->at(0)) + $finalPriceType = $this->getMock(FinalPrice::class, [], [], '', false); + + $finalPriceType->expects($this->once()) ->method('getAmount') ->will($this->returnValue($finalPriceAmount)); - $finalPriceType->expects($this->at(1)) - ->method('getMinimalPrice') - ->will($this->returnValue($minimalPriceAmount)); $this->priceInfo->expects($this->once()) ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) - ->will($this->returnValue($finalPriceType)); + ->with(FinalPrice::PRICE_CODE) + ->willReturn($finalPriceType); + + $this->object->setDisplayMinimalPrice($displayMininmalPrice); $this->assertTrue($this->object->showMinimalPrice()); } diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Indexer.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Indexer.php new file mode 100644 index 0000000000000..0cf4f2bca24d5 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Indexer.php @@ -0,0 +1,35 @@ +transport = $transport; + } + + /** + * Creates Website folder in root directory. + * + * @param string $websiteCode + * @throws \Exception + */ + public function create($websiteCode) + { + $curl = $this->transport; + $curl->addOption(CURLOPT_HEADER, 1); + $curl->write($this->prepareUrl($websiteCode), [], CurlInterface::GET); + $curl->read(); + $curl->close(); + } + + /** + * Prepare url. + * + * @param string $websiteCode + * @return string + */ + private function prepareUrl($websiteCode) + { + return $_ENV['app_frontend_url'] . self::URL . '?website_code=' . urlencode($websiteCode); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct.xml index be4c15784208b..7efc2bf12371b 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct.xml @@ -90,7 +90,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml index e4c57688bbd66..e6a6abdc338bd 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml @@ -17,7 +17,9 @@ bundle_dynamic_with_category - Main Website + + default + default_dynamic @@ -44,7 +46,9 @@ taxable_goods - Main Website + + default + Yes @@ -83,7 +87,9 @@ Yes Together - Main Website + + default + Yes @@ -117,7 +123,9 @@ 1 No - Main Website + + default + default_subcategory @@ -137,7 +145,9 @@ bundle_dynamic_with_category - Main Website + + default + default_subcategory @@ -162,7 +172,9 @@ 1 No - Main Website + + default + Separately @@ -193,7 +205,9 @@ Yes Together - Main Website + + default + Yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.php index d0d208d5faf7b..1dc96e39ca026 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.php @@ -53,9 +53,14 @@ public function fill(FixtureInterface $fixture, SimpleElement $element = null) $storeSwitcherBlock->find($this->dropdownBlock, Locator::SELECTOR_CSS, 'liselectstore')->setValue($store); $modalElement = $this->browser->find($this->confirmModal); /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ - $modal = $this->blockFactory->create('Magento\Ui\Test\Block\Adminhtml\Modal', ['element' => $modalElement]); + $modal = $this->blockFactory->create( + \Magento\Ui\Test\Block\Adminhtml\Modal::class, + ['element' => $modalElement] + ); $modal->acceptAlert(); + $modal->waitModalWindowToDisappear(); } + return parent::fill($fixture, $element); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml index 09240d9cf319b..6fa3b543f38c5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml @@ -24,7 +24,7 @@ input[name='name'] - [name="use_default[]"][value="name"] + [name="use_default[name]"] checkbox @@ -90,6 +90,10 @@ input input[name='url_key'] + + checkbox + input[name='use_default[url_key]'] + input input[name='meta_title'] diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php index 3bf28dd49164a..3adee2a605e96 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php @@ -7,12 +7,18 @@ namespace Magento\Catalog\Test\Block\Adminhtml\Category\Edit; use Magento\Backend\Test\Block\FormPageActions; +use Magento\Mtf\Client\Locator; /** * Category page actions. */ class PageActions extends FormPageActions { + /** + * Top page element to implement a scrolling in case of floating blocks overlay. + */ + const TOP_ELEMENT_TO_SCROLL = 'header.page-header'; + /** * Locator for "OK" button in warning block * @@ -20,6 +26,20 @@ class PageActions extends FormPageActions */ protected $warningBlock = '.ui-widget-content .ui-dialog-buttonset button:first-child'; + /** + * Change Store View selector. + * + * @var string + */ + protected $storeChangeButton = '#store-change-button'; + + /** + * Selector for confirm. + * + * @var string + */ + protected $confirmModal = '.confirm._show[data-role=modal]'; + /** * Click on "Save" button * @@ -33,4 +53,23 @@ public function save() $warningBlock->click(); } } + + /** + * Select Store View. + * + * @param string $name + * @return void + */ + public function selectStoreView($name) + { + $this->browser->find(self::TOP_ELEMENT_TO_SCROLL)->hover(); + $this->_rootElement->find($this->storeChangeButton)->click(); + $this->waitForElementVisible($name, Locator::SELECTOR_LINK_TEXT); + $this->_rootElement->find($name, Locator::SELECTOR_LINK_TEXT)->click(); + $element = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create(\Magento\Ui\Test\Block\Adminhtml\Modal::class, ['element' => $element]); + $modal->acceptAlert(); + $this->waitForElementVisible($this->storeChangeButton); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php index 729aa0ed0be66..7046c2e22b9dc 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php @@ -40,6 +40,9 @@ class Price extends \Magento\Catalog\Test\Block\AbstractPriceBlock ], 'price_including_tax' => [ 'selector' => '.price-including-tax .price' + ], + 'minimal_price' => [ + 'selector' => '.minimal-price-link' ] ]; @@ -161,4 +164,14 @@ public function isOldPriceVisible() { return $this->getTypePriceElement('old_price')->isVisible(); } + + /** + * This method returns if the special price is visible. + * + * @return bool + */ + public function isMinimalPriceVisible() + { + return $this->getTypePriceElement('minimal_price')->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php index 4db4a9b12696a..c7a9cdd94a060 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php @@ -27,7 +27,8 @@ class AssertCategoryForm extends AbstractAssertForm */ protected $skippedFixtureFields = [ 'parent_id', - 'id' + 'id', + 'store_id', ]; /** @@ -45,7 +46,10 @@ public function processAssert( ) { $catalogCategoryIndex->open(); $catalogCategoryIndex->getTreeCategories()->selectCategory($category, true); - + if ($category->hasData('store_id')) { + $storeName = $category->getStoreId()['source']->getName(); + $catalogCategoryEdit->getFormPageActions()->selectStoreView($storeName); + } $fixtureData = $this->prepareFixtureData($category->getData()); $formData = $catalogCategoryEdit->getEditForm()->getData($category); $error = $this->verifyData($this->sortData($fixtureData), $this->sortData($formData)); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml index 2fd1f97140ed4..5f920b452d3a0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml @@ -76,7 +76,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductVirtual.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductVirtual.xml index c113aff5e0d9d..be34fe83d87a7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductVirtual.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductVirtual.xml @@ -78,7 +78,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml index 61a8981b0f3af..e35932a2c5ae4 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml @@ -20,7 +20,7 @@ - + @@ -41,6 +41,7 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/WebsiteIds.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/WebsiteIds.php new file mode 100644 index 0000000000000..ede8093ebd6f2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/WebsiteIds.php @@ -0,0 +1,144 @@ +fixtureFactory = $fixtureFactory; + $this->params = $params; + $this->fixtureData = $data; + } + + /** + * Return prepared data set. + * + * @param string $key [optional] + * @return mixed + * @throws \Exception + */ + public function getData($key = null) + { + if (empty($this->fixtureData)) { + throw new \Exception("Data must be set"); + } + + foreach ($this->fixtureData as $dataset) { + if (is_array($dataset) && isset($dataset['websites'])) { + foreach ($dataset['websites'] as $website) { + $this->websites[] = $website; + } + } else { + $this->createStore($dataset); + } + } + + return parent::getData($key); + } + + /** + * Create store. + * + * @param array|object $dataset + * @return void + */ + private function createStore($dataset) + { + if ($dataset instanceof Store) { + $store = $dataset; + } elseif (is_array($dataset)) { + $store = isset($dataset['store']) ? $dataset['store'] : + (isset($dataset['dataset']) ? $this->fixtureFactory->createByCode('store', $dataset) : null); + } + if (isset($store)) { + $this->setWebsiteStoreData($store); + } + } + + /** + * Set website and store data. + * + * @param Store $store + * @return void + */ + private function setWebsiteStoreData(Store $store) + { + if (!$store->getStoreId()) { + $store->persist(); + } + $website = $store->getDataFieldConfig('group_id')['source'] + ->getStoreGroup()->getDataFieldConfig('website_id')['source']->getWebsite(); + $this->data[] = $website->getName(); + $this->websites[] = $website; + $this->stores[] = $store; + } + + /** + * Return stores. + * + * @return array + */ + public function getStores() + { + return $this->stores; + } + + /** + * Return website codes. + * + * @return array + */ + public function getWebsites() + { + return $this->websites; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php index 8087e6363c718..2440f6e800a18 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php @@ -415,12 +415,25 @@ protected function prepareCategory() protected function prepareWebsites() { if (!empty($this->fields['product']['website_ids'])) { - foreach ($this->fields['product']['website_ids'] as $key => $website) { - $website = isset($this->mappingData['website_ids'][$website]) - ? $this->mappingData['website_ids'][$website] - : $website; - $this->fields['product']['website_ids'][$key] = $website; + if (isset($this->fixture->getDataFieldConfig('website_ids')['source'])) { + $webSitesSource = $this->fixture->getDataFieldConfig('website_ids')['source']; + + foreach ($webSitesSource->getWebsites() as $key => $website) { + $this->fields['product']['website_ids'][$key] = $website->getWebsiteId(); + } + + } else { + foreach ($this->fields['product']['website_ids'] as $key => $website) { + $website = isset($this->mappingData['website_ids'][$website]) + ? $this->mappingData['website_ids'][$website] + : $website; + $this->fields['product']['website_ids'][$key] = $website; + } } + } else { + $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager() + ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']); + $this->fields['product']['website_ids'][] = $website->getWebsiteId(); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml index 7a8a629ca765b..f2ce59cc091d2 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml @@ -26,7 +26,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -55,7 +57,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -84,7 +88,9 @@ default_subcategory - Main Website + + default + simple_order_default @@ -111,7 +117,9 @@ taxable_goods - Main Website + + default + Catalog, Search product-10-dollar-%isolation% @@ -139,7 +147,9 @@ taxable_goods - Main Website + + default + Catalog, Search product-20-dollar-%isolation% @@ -159,7 +169,9 @@ 560 - Main Website + + default + Catalog, Search @@ -186,7 +198,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -214,7 +228,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -239,7 +255,9 @@ 100 - Main Website + + default + simple-product-%isolation% @@ -266,7 +284,9 @@ product_40_dollar simple-product-%isolation% - Main Website + + default + @@ -291,7 +311,9 @@ simple_with_category - Main Website + + default + simple-product-%isolation% @@ -316,7 +338,9 @@ default_subcategory - Main Website + + default + simple_with_category simple-product-%isolation% @@ -340,7 +364,9 @@ In Stock - Main Website + + default + @@ -361,7 +387,9 @@ This item has weight 100 - Main Website + + default + simple-product-%isolation% @@ -389,7 +417,9 @@ 1 Yes - Main Website + + default + Yes @@ -417,7 +447,9 @@ In Stock - Main Website + + default + simple-product-%isolation% @@ -446,7 +478,9 @@ default_subcategory - Main Website + + default + simple-product-%isolation% @@ -469,7 +503,9 @@ 9 - Main Website + + default + simple-product-%isolation% @@ -495,7 +531,9 @@ <p>dfj_full</p> Yes - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -519,7 +557,9 @@ <p>Simple with Weight 0.1</p> Yes - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -543,7 +583,9 @@ <p>Simple with Weight 150.1</p> Yes - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -568,7 +610,9 @@ Yes <p>abc_short</p> - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -590,7 +634,9 @@ 100 - Main Website + + default + simple-product-%isolation% @@ -657,7 +703,9 @@ default_subcategory - Main Website + + default + simple-product-%isolation% @@ -678,7 +726,9 @@ In Stock - Main Website + + default + two_options @@ -711,7 +761,9 @@ simple_drop_down_with_one_option_percent_price - Main Website + + default + default_subcategory @@ -760,7 +812,9 @@ 100 - Main Website + + default + simple-product-%isolation% @@ -784,7 +838,9 @@ taxable_goods - Main Website + + default + Catalog, Search @@ -812,7 +868,9 @@ taxable_goods - Main Website + + default + Catalog, Search @@ -841,7 +899,9 @@ taxable_goods - Main Website + + default + Not Visible Individually @@ -869,7 +929,9 @@ taxable_goods - Main Website + + default + Catalog, Search @@ -907,7 +969,9 @@ simple-product-%isolation% - Main Website + + default + @@ -930,7 +994,9 @@ taxable_goods - Main Website + + default + Catalog, Search @@ -965,7 +1031,9 @@ more_is_cheaper - Main Website + + default + @@ -989,7 +1057,9 @@ default_anchor_subcategory - Main Website + + default + simple_with_category simple-product-%isolation% @@ -1006,7 +1076,9 @@ taxable_goods - Main Website + + default + Simple Product With Fpt %isolation% sku_simple_product_%isolation% @@ -1042,7 +1114,9 @@ taxable_goods - Main Website + + default + Simple Product With Fpt %isolation% sku_simple_product_%isolation% @@ -1082,7 +1156,9 @@ taxable_goods - Main Website + + default + Catalog, Search diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml index fb564aa36328a..c485e1d3b9669 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml @@ -13,7 +13,9 @@ Yes - Main Website + + default + virtual-product%isolation% Catalog, Search @@ -47,7 +49,9 @@ This item has no weight - Main Website + + default + @@ -65,7 +69,9 @@ taxable_goods - Main Website + + default + @@ -75,7 +81,9 @@ Yes - Main Website + + default + virtual-product%isolation% Catalog, Search @@ -102,7 +110,9 @@ Yes - Main Website + + default + virtual-product%isolation% Catalog, Search @@ -131,7 +141,9 @@ Yes - Main Website + + default + virtual-product%isolation% Catalog, Search @@ -155,7 +167,9 @@ taxable_goods - Main Website + + default + virtual-product%isolation% Virtual product %isolation% diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml index 88f2670684816..46a7b9b22cf21 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml @@ -17,6 +17,17 @@ + + Category%isolation% + custom%isolation% + Yes + Yes + + default_category + + Yes + + Default Category 1 diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml index e4516d83075f3..3b942758eeb8c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml @@ -34,5 +34,21 @@ 1 + + + default + 0 + Website + 1 + + + + + default + 0 + Global + 0 + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php index 24db0bf77a42f..e5bf7085fdb9b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php @@ -61,14 +61,12 @@ class UpdateCategoryEntityTest extends Injectable /** * Inject page end prepare default category * - * @param Category $initialCategory * @param CatalogCategoryIndex $catalogCategoryIndex * @param CatalogCategoryEdit $catalogCategoryEdit * @param FixtureFactory $fixtureFactory - * @return array + * @return void */ public function __inject( - Category $initialCategory, CatalogCategoryIndex $catalogCategoryIndex, CatalogCategoryEdit $catalogCategoryEdit, FixtureFactory $fixtureFactory @@ -76,8 +74,6 @@ public function __inject( $this->fixtureFactory = $fixtureFactory; $this->catalogCategoryIndex = $catalogCategoryIndex; $this->catalogCategoryEdit = $catalogCategoryEdit; - $initialCategory->persist(); - return ['initialCategory' => $initialCategory]; } /** @@ -89,6 +85,7 @@ public function __inject( */ public function test(Category $category, Category $initialCategory) { + $initialCategory->persist(); $this->catalogCategoryIndex->open(); $this->catalogCategoryIndex->getTreeCategories()->selectCategory($initialCategory); $this->catalogCategoryEdit->getEditForm()->fill($category); @@ -110,11 +107,16 @@ protected function prepareCategory(Category $category, Category $initialCategory ? $category->getDataFieldConfig('parent_id')['source']->getParentCategory() : $initialCategory->getDataFieldConfig('parent_id')['source']->getParentCategory(); + $rewriteData = ['parent_id' => ['source' => $parentCategory]]; + if ($category->hasData('store_id')) { + $rewriteData['store_id'] = ['source' => $category->getDataFieldConfig('store_id')['source']->getStore()]; + } + $data = [ 'data' => array_merge( $initialCategory->getData(), $category->getData(), - ['parent_id' => ['source' => $parentCategory]] + $rewriteData ) ]; diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml index 2ed97cfd61834..773dcda5d045d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml @@ -51,5 +51,14 @@ + + + default_with_custom_url + default_category + custom + Yes + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php index 468ecc2395ef6..c063e27836161 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php @@ -8,6 +8,7 @@ use Magento\Checkout\Test\Fixture\Cart; use Magento\Checkout\Test\Page\CheckoutCart; +use Magento\Customer\Test\Fixture\Customer; use Magento\Mtf\Constraint\AbstractConstraint; /** @@ -20,12 +21,21 @@ class AssertDiscountInShoppingCart extends AbstractConstraint /** * Assert that discount is equal to expected. * + * @param Customer $customer * @param CheckoutCart $checkoutCart * @param Cart $cart * @return void */ - public function processAssert(CheckoutCart $checkoutCart, Cart $cart) - { + public function processAssert( + Customer $customer, + CheckoutCart $checkoutCart, + Cart $cart + ) { + $loginStep = $this->objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $customer] + ); + $loginStep->run(); $checkoutCart->open(); $checkoutCart->getTotalsBlock()->waitForUpdatedTotals(); \PHPUnit_Framework_Assert::assertEquals( @@ -33,6 +43,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart) $checkoutCart->getTotalsBlock()->getDiscount(), 'Discount amount in the shopping cart not equals to discount amount from fixture.' ); + $loginStep->cleanUp(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml index cf101cde54916..c02a109e75c90 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml @@ -10,9 +10,16 @@ to_maintain:yes Verify cms page grid sorting + 2 + cmsPage + default + + - + - + ID - Created + URL Key Magento\Cms\Test\Page\Adminhtml\CmsPageIndex getCmsPageGridBlock @@ -29,7 +36,7 @@ default ID - Created + Identifier Magento\Cms\Test\Page\Adminhtml\CmsBlockIndex getCmsBlockGrid diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml index 9f9174731a599..fa3338eb80170 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml @@ -14,7 +14,7 @@ repository_class="Magento\Config\Test\Repository\ConfigData" handler_interface="Magento\Config\Test\Handler\ConfigData\ConfigDataInterface" class="Magento\Config\Test\Fixture\ConfigData"> - + diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php new file mode 100644 index 0000000000000..b25a7c383fa52 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php @@ -0,0 +1,199 @@ +fixtureFactory = $fixtureFactory; + $this->params = $params; + $this->fixtureData = $data; + } + + /** + * Return prepared data set. + * + * @param string $key [optional] + * @return mixed + */ + public function getData($key = null) + { + if ($this->data === null) { + if (isset($this->fixtureData['scope']['scope_type'])) { + $this->scopeData = $this->fixtureData['scope']; + $this->scopeType = $this->fixtureData['scope']['scope_type']; + $this->setLevel = $this->fixtureData['scope']['set_level']; + $this->prepareScopeData(); + unset($this->fixtureData['scope']); + } + $this->data = $this->replacePlaceholders($this->fixtureData); + } + + return parent::getData($key); + } + + /** + * Replace placeholders in parameters array. + * + * @param array $data + * @return array + */ + private function replacePlaceholders(array $data) + { + foreach ($data as &$params) { + $params = array_map(function ($value) { + if (is_string($value)) { + $value = str_replace( + '{{basic_url_to_secure}}', + preg_replace('/(http[s]?)/', 'https', $_ENV['app_frontend_url']), + $value + ); + $value = str_replace( + '{{basic_url_to_unsecure}}', + preg_replace('/(http[s]?)/', 'http', $_ENV['app_frontend_url']), + $value + ); + } + return $value; + }, $params); + } + + return $data; + } + + /** + * Prepare scope data. + * + * @return void + * @throws \Exception + */ + private function prepareScopeData() + { + if (isset($this->scopeData['dataset'])) { + /** @var Store|Website $store */ + $this->scope = $this->fixtureFactory->createByCode( + $this->scopeType, + ['dataset' => $this->scopeData['dataset']] + ); + if (!$this->scope->hasData($this->scopeType . '_id')) { + $this->scope->persist(); + } + } elseif (isset($this->scopeData['fixture'])) { + $this->scope = $this->scopeData['fixture']; + } else { + throw new \Exception('Parameters "dataset" and "fixture" aren\'t identify.'); + } + + $this->prepareScope(); + } + + /** + * Prepare scope. + * + * @return void + * @throws \Exception + */ + private function prepareScope() + { + if ($this->setLevel == self::STORE_CODE && $this->scopeType == self::WEBSITE_CODE) { + throw new \Exception('Store level can\'t set to ["scope_type" = "website"].'); + } elseif ($this->setLevel == self::WEBSITE_CODE && $this->scopeType == self::STORE_CODE) { + $this->scopeType = $this->setLevel; + $this->scope = $this->scope + ->getDataFieldConfig('group_id')['source']->getStoreGroup() + ->getDataFieldConfig('website_id')['source']->getWebsite(); + } + } + + /** + * Return Store View or Website fixture. + * + * @return Store|Website + */ + public function getScope() + { + return $this->scope; + } + + /** + * Get get scope type [website|store]. + * + * @return string + */ + public function getScopeType() + { + return $this->scopeType; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php b/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php index c34f5951c03b3..50f11310abc3a 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php @@ -10,6 +10,9 @@ use Magento\Mtf\Handler\Curl as AbstractCurl; use Magento\Mtf\Util\Protocol\CurlTransport; use Magento\Mtf\Util\Protocol\CurlTransport\BackendDecorator; +use Magento\Config\Test\Fixture\ConfigData\Section; +use Magento\Store\Test\Fixture\Store; +use Magento\Store\Test\Fixture\Website; /** * Setting config. @@ -29,6 +32,13 @@ class Curl extends AbstractCurl implements ConfigDataInterface ], ]; + /** + * FixtureInterface object. + * + * @var FixtureInterface + */ + private $fixture; + /** * Post request for setting configuration. * @@ -37,6 +47,7 @@ class Curl extends AbstractCurl implements ConfigDataInterface */ public function persist(FixtureInterface $fixture = null) { + $this->fixture = $fixture; $data = $this->prepareData($fixture); foreach ($data as $scope => $item) { $this->applyConfigSettings($item, $scope); @@ -132,6 +143,26 @@ protected function applyConfigSettings(array $data, $section) */ protected function getUrl($section) { - return $_ENV['app_backend_url'] . 'admin/system_config/save/section/' . $section; + return $_ENV['app_backend_url'] . 'admin/system_config/save/section/' . $section . $this->getStoreViewUrl(); + } + + /** + * Get store view url. + * + * @return string + */ + private function getStoreViewUrl() + { + $result = ''; + /** @var Section $source */ + $source = $this->fixture->getDataFieldConfig('section')['source']; + /** @var Store|Website $scope */ + $scope = $source->getScope(); + if ($scope !== null) { + $code = $source->getScopeType(); + $result = $code . '/' . $scope->getData($code . '_id'); + } + + return $result ? '/' . $result : ''; } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php index 45bd430cb23eb..a6f9b9c48c4c8 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php @@ -41,5 +41,12 @@ protected function assertPrice(FixtureInterface $product, CatalogCategoryView $c 'Product special price on category page is not correct.' ); } + + if (!$product->hasData('tier_price')) { + \PHPUnit_Framework_Assert::assertNotTrue( + $priceBlock->isMinimalPriceVisible(), + 'Minimal price block mustn\'t be visible on category page.' + ); + } } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml index 70c613660d542..5964b0a66a976 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml @@ -81,7 +81,7 @@ - + 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 49a8fcd5a8bae..b57afacd2c308 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 @@ -29,7 +29,9 @@ In Stock - Main Website + + default + default @@ -60,7 +62,9 @@ In Stock - Main Website + + default + default @@ -92,7 +96,9 @@ In Stock - Main Website + + default + default @@ -120,7 +126,9 @@ In Stock - Main Website + + default + default @@ -152,7 +160,9 @@ In Stock - Main Website + + default + default @@ -184,7 +194,9 @@ In Stock - Main Website + + default + default @@ -214,7 +226,9 @@ default - Main Website + + default + default @@ -242,7 +256,9 @@ In Stock - Main Website + + default + default @@ -274,7 +290,9 @@ In Stock - Main Website + + default + default @@ -302,7 +320,9 @@ default_subcategory - Main Website + + default + two_options_with_fixed_price @@ -329,7 +349,9 @@ This item has weight 1 - Main Website + + default + two_variations_with_fixed_price @@ -365,7 +387,9 @@ In Stock - Main Website + + default + custom_attribute_set @@ -393,7 +417,9 @@ default_subcategory - Main Website + + default + two_options_by_one_dollar @@ -409,5 +435,37 @@ price_40 + + + Configurable product %isolation% + test-configurable-product-%isolation% + sku_configurable_product_%isolation% + + taxable_goods + + This item has weight + 1 + + + default + + + custom_store + + + + default_subcategory + + + two_options_ten_dollars + + + custom_attribute_set + + + 15 + price_15 + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml index 66a4748e71288..09899f446a76d 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -662,5 +662,37 @@ + + + + + + + option_key_1_%isolation% + 10 + Yes + + + option_key_2_%isolation% + 10 + Yes + + + + + + catalogProductAttribute::attribute_type_dropdown_two_options + + + + 10 + 1 + + + 20 + 2 + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml index ae055f628d907..74de6f99ade2c 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml @@ -17,5 +17,9 @@ 11 + + 15 + 15 + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductCustomWebsiteTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductCustomWebsiteTest.php new file mode 100644 index 0000000000000..286b30d4510d1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductCustomWebsiteTest.php @@ -0,0 +1,40 @@ + Configuration > Catalog > Catalog > Price) + * 2. Create Additional Website, Store, Store View. + * 3. Create Configurable product with two variations, price for all variations is 10$ and assign it to both websites. + * 4. Open all simple products, which are assigned to configurable and change their price in Default Store View to 15$ + * 5. Do reindex and clear magento cache + * 6. Open on storefront on main website category with configurable product + * 7. "As low as" price not shown for configurable product + * + * @group Configurable_Product_(MX) + * @ZephyrId MAGETWO-64720 + */ +class UpdateConfigurableProductCustomWebsiteTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const DOMAIN = 'MX'; + /* end tags */ + + /** + * Test update Configurable product with custom website run. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductCustomWebsiteTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductCustomWebsiteTest.xml new file mode 100644 index 0000000000000..ca9456f7d6445 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductCustomWebsiteTest.xml @@ -0,0 +1,18 @@ + + + + + + price_per_website + configurableProduct::two_variations_two_websites + default + 15.00 + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateSimplesInConfigurablePerStoreStep.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateSimplesInConfigurablePerStoreStep.php new file mode 100644 index 0000000000000..4e7e0c4b61d83 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateSimplesInConfigurablePerStoreStep.php @@ -0,0 +1,134 @@ +indexer = $indexer; + $this->cache = $cache; + $this->store = $store; + $this->catalogProductEdit = $catalogProductEdit; + $this->productGrid = $productGrid; + $this->product = $product; + $this->updatedSimple = $updatedSimple; + } + + /** + * Update simple products data in configurable for store. + * + * @return void + */ + public function run() + { + if (!$this->store) { + return; + } + + $simpleProductsArray = []; + $configurableAttributes = $this->product->getConfigurableAttributesData(); + + if (isset($configurableAttributes['matrix'])) { + foreach ($configurableAttributes['matrix'] as $matrixItem) { + $simpleProductsArray[] = $matrixItem['sku']; + } + } + + foreach ($simpleProductsArray as $simpleProductSku) { + //open product + $filter = ['sku' => $simpleProductSku]; + $this->productGrid->open(); + $this->productGrid->getProductGrid()->searchAndOpen($filter); + //update + $this->catalogProductEdit->getFormPageActions()->changeStoreViewScope($this->store); + $this->catalogProductEdit->getProductForm()->fill($this->updatedSimple); + $this->catalogProductEdit->getFormPageActions()->save(); + } + + $this->indexer->reindex(); + $this->cache->flush(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml index 837aeb382680c..f114a565bd394 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml @@ -13,4 +13,9 @@ + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml index 9640e19950b95..a1cb8d84ce8b4 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml @@ -10,10 +10,17 @@ to_maintain:yes Verify customer page grid sorting + 2 + customer + default ID Customer Since + + - + - + Magento\Customer\Test\Page\Adminhtml\CustomerIndex getCustomerGridBlock diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml index f8d16a9de0121..c7873aeb46994 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml @@ -86,7 +86,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml index 42680d9f9377b..848401b881e45 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml @@ -30,7 +30,9 @@ This item has no weight - Main Website + + default + downloadable_default @@ -54,7 +56,9 @@ Yes Catalog, Search - Main Website + + default + with_two_separately_links @@ -81,7 +85,9 @@ Yes Catalog, Search - Main Website + + default + with_two_separately_links @@ -112,7 +118,9 @@ Catalog, Search - Main Website + + default + with_two_separately_links @@ -142,7 +150,9 @@ Catalog, Search - Main Website + + default + with_two_separately_links @@ -176,7 +186,9 @@ taxable_goods - Main Website + + default + downloadable_one_dollar_product_with_no_separated_link diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml index 4a0660e4d991f..0b934136929c1 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml @@ -70,7 +70,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml index 5b09e5f46c408..a8713fd3fec80 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml @@ -26,7 +26,9 @@ In Stock - Main Website + + default + default @@ -52,7 +54,9 @@ Out of Stock - Main Website + + default + default @@ -82,7 +86,9 @@ In Stock - Main Website + + default + default @@ -108,7 +114,9 @@ In Stock - Main Website + + default + default diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml index 097187e1454ff..e8e6b987ef655 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml @@ -27,7 +27,9 @@ taxable_goods - Main Website + + default + Catalog, Search @@ -58,7 +60,9 @@ taxable_goods - Main Website + + default + No diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml index b76ac44f92dd4..6225acda86698 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml @@ -30,7 +30,9 @@ one_variation_one_dollar - Main Website + + default + custom_attribute_set diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/CatalogProductSimple.xml index e822bf08044d5..8864204eab354 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/CatalogProductSimple.xml @@ -26,7 +26,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-with-video-%isolation% @@ -61,7 +63,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-with-video-%isolation% diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.xml b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.xml index e3922e303d571..a21202d4c5738 100644 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.xml +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.xml @@ -52,8 +52,8 @@ test_type:extended_acceptance_test product_with_video_vimeo simple_product_with_category_%isolation% - https://vimeo.com/21776334 - Foo Fighters - "Walk" - Official Music Video (HD) + https://vimeo.com/103756396 + XO Stereo - Show And Tell OFFICIAL MUSIC VIDEO play_if_base diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php b/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php index eee1eb7b5815a..9f53fac6e4441 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php @@ -11,6 +11,11 @@ use Magento\Mtf\Util\Protocol\CurlInterface; use Magento\Mtf\Util\Protocol\CurlTransport; use Magento\Mtf\Util\Protocol\CurlTransport\BackendDecorator; +use Magento\Store\Test\Fixture\Website as WebsiteFixture; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\Config\DataInterface; +use Magento\Mtf\System\Event\EventManagerInterface; +use Magento\Mtf\Util\Command\Website; /** * Class Curl @@ -18,6 +23,45 @@ */ class Curl extends AbstractCurl implements WebsiteInterface { + /** + * Website folder creation class instance. + * + * @var Website + */ + private $website; + + /** + * Website fixture. + * + * @var WebsiteFixture + */ + private $fixture; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + private $fixtureFactory; + + /** + * @constructor + * @param DataInterface $configuration + * @param EventManagerInterface $eventManager + * @param Website $website + * @param FixtureFactory $fixtureFactory + */ + public function __construct( + DataInterface $configuration, + EventManagerInterface $eventManager, + Website $website, + FixtureFactory $fixtureFactory + ) { + parent::__construct($configuration, $eventManager); + $this->website = $website; + $this->fixtureFactory = $fixtureFactory; + } + /** * POST request for creating Website * @@ -37,7 +81,19 @@ public function persist(FixtureInterface $fixture = null) throw new \Exception("Website entity creating by curl handler was not successful! Response: $response"); } - return ['website_id' => $this->getWebSiteIdByWebsiteName($fixture->getName())]; + $websiteId = $this->getWebSiteIdByWebsiteName($fixture->getName()); + + // Update website fixture data. + $this->fixture = $this->fixtureFactory->createByCode( + 'website', + ['data' => array_merge($fixture->getData(), ['website_id' => $websiteId])] + ); + $data['website']['website_id'] = $websiteId; + // Creates Website folder in root directory. + $this->website->create($data['website']['code']); + $this->setConfiguration($data); + + return ['website_id' => $websiteId]; } /** @@ -85,4 +141,24 @@ protected function prepareData(FixtureInterface $fixture) return $data; } + + /** + * Set Website configuration Base url. + * + * @param array $data + * @return void + * @throws \Exception + */ + private function setConfiguration(array $data) + { + $configData = [ + 'web/unsecure/base_link_url' => [ + 'value' => '{{unsecure_base_url}}websites/' . $data['website']['code'] . '/', + ], + 'scope' => ['fixture' => $this->fixture, 'scope_type' => 'website', 'set_level' => 'website'] + ]; + + $configFixture = $this->fixtureFactory->createByCode('configData', ['data' => $configData]); + $configFixture->persist(); + } } 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 index 098f28965d65d..175209ab36c4a 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml @@ -32,7 +32,9 @@ default_subcategory - Main Website + + default + custom_attribute_set diff --git a/dev/tests/functional/utils/website.php b/dev/tests/functional/utils/website.php new file mode 100644 index 0000000000000..0ed76714e1bab --- /dev/null +++ b/dev/tests/functional/utils/website.php @@ -0,0 +1,32 @@ +objectManager = Bootstrap::getObjectManager(); + + $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + + $this->appState = $this->objectManager->get(State::class); + $this->appState->setAreaCode(Area::AREA_FRONTEND); + + $this->phtml = $this->objectManager->create(Php::class); + + $this->templateEnginePool = $this->objectManager->get(TemplateEnginePool::class); + + $enginesReflection = new \ReflectionProperty( + $this->templateEnginePool, + 'engines' + ); + $enginesReflection->setAccessible(true); + $enginesReflection->setValue($this->templateEnginePool, ['phtml' => $this->phtml]); + + $this->rendererPool = $this->objectManager->create(RendererPool::class); + + $this->rendererPool->setData( + [ + 'default' => + [ + 'default_amount_render_class' => Amount::class, + 'default_amount_render_template' => 'Magento_Catalog::product/price/amount/default.phtml' + ] + ] + ); + + $this->saleableItem = $this->productRepository->get('tier_prices'); + $this->finalPrice = $this->objectManager->create( + FinalPrice::class, + [ + 'saleableItem' => $this->saleableItem, + 'quantity' => null + ] + ); + + $this->finalPriceBox = $this->objectManager->create( + FinalPriceBox::class, + [ + 'saleableItem' => $this->saleableItem, + 'price' => $this->finalPrice, + 'rendererPool' => $this->rendererPool + ] + ); + + $this->finalPriceBox->setData('price_id', 'test_price_id'); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testRenderAmountMinimalProductWithTierPricesShouldShowMinTierPrice() + { + $result = $this->finalPriceBox->renderAmountMinimal(); + $this->assertContains('$5.00', $result); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_different_store_prices.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + */ + public function testProductSetDifferentStorePricesWithoutTierPriceShouldNotShowAsLowAs() + { + $this->assertEmpty($this->finalPriceBox->renderAmountMinimal()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices.php new file mode 100644 index 0000000000000..be0e890742102 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices.php @@ -0,0 +1,58 @@ +create(IndexerRegistry::class); +$indexer = $indexerRegistry->get('catalogsearch_fulltext'); + +$indexer->reindexAll(); + +/** @var $product Product */ +$product = $objectManager->create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('tier_prices') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); + +$product->setStoreId($store->getId()); +$product->setPrice(15); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices_rollback.php new file mode 100644 index 0000000000000..4c4be750e7a5d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices_rollback.php @@ -0,0 +1,25 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()-> +create(\Magento\Catalog\Model\ProductRepository::class); +try { + $product = $repository->get('tier_prices'); + $product->delete(); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Entity already deleted +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +require __DIR__ . '/../../Store/_files/core_fixturestore_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php new file mode 100644 index 0000000000000..a5fad2e96e4a4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php @@ -0,0 +1,75 @@ +reinitialize(); + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +$tierPrices = []; +/** @var \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory::class); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 2, + 'value' => 8 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 5, + 'value' => 5 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 3, + 'value' => 5 + ] + ] +); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('tier_prices') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setTierPrices($tierPrices) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepositoryFactory */ +$productRepositoryFactory = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$productRepositoryFactory->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as_rollback.php new file mode 100644 index 0000000000000..310b5445e9718 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as_rollback.php @@ -0,0 +1,23 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Model\ProductRepository::class); +try { + $product = $repository->get('tier_prices'); + $product->delete(); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Entity already deleted +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php index 615c40498c94f..ec28cab76b87a 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php @@ -7,8 +7,14 @@ use Magento\CatalogImportExport\Model\AbstractProductExportImportTestCase; +/** + * Configurable product import test. + */ class ConfigurableTest extends AbstractProductExportImportTestCase { + /** + * @return array + */ public function exportImportDataProvider() { return [ @@ -21,6 +27,15 @@ public function exportImportDataProvider() ], ['_cache_instance_products', '_cache_instance_configurable_attributes'], ], + 'configurable-product-12345' => [ + [ + 'Magento/ConfigurableProduct/_files/product_configurable_12345.php' + ], + [ + '12345', + ], + ['_cache_instance_products', '_cache_instance_configurable_attributes'], + ], ]; } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php index 8792e95736a34..210369c8ac6af 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php @@ -6,21 +6,17 @@ namespace Magento\ConfigurableImportExport\Model\Import\Product\Type; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\App\Bootstrap; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\ImportExport\Model\Import; /** + * Product type configurable import test. + * * @magentoAppArea adminhtml * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ConfigurableTest extends \PHPUnit_Framework_TestCase { - /** - * Configurable product test Name - */ - const TEST_PRODUCT_NAME = 'Configurable 1'; - /** * Configurable product test Type */ @@ -31,13 +27,6 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase */ protected $model; - /** - * Configurable product options SKU list - * - * @var array - */ - protected $optionSkuList = ['Configurable 1-Option 1', 'Configurable 1-Option 2']; - /** * @var \Magento\Framework\ObjectManagerInterface */ @@ -59,13 +48,35 @@ protected function setUp() } /** + * @return array + */ + public function configurableImportDataProvider() + { + return [ + 'Configurable 1' => [ + __DIR__ . '/../../_files/import_configurable.csv', + 'Configurable 1', + ['Configurable 1-Option 1', 'Configurable 1-Option 2'], + ], + '12345' => [ + __DIR__ . '/../../_files/import_configurable_12345.csv', + '12345', + ['Configurable 1-Option 1', 'Configurable 1-Option 2'], + ], + ]; + } + + /** + * @param string $pathToFile Path to import file + * @param string $productName Name/sku of configurable product + * @param array $optionSkuList Name of variations for configurable product * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php * @magentoAppArea adminhtml + * @dataProvider configurableImportDataProvider */ - public function testConfigurableImport() + public function testConfigurableImport($pathToFile, $productName, $optionSkuList) { // import data from CSV file - $pathToFile = __DIR__ . '/../../_files/import_configurable.csv'; $filesystem = $this->objectManager->create( \Magento\Framework\Filesystem::class ); @@ -92,23 +103,23 @@ public function testConfigurableImport() /** @var \Magento\Catalog\Model\ResourceModel\Product $resource */ $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class); - $productId = $resource->getIdBySku(self::TEST_PRODUCT_NAME); + $productId = $resource->getIdBySku($productName); $this->assertTrue(is_numeric($productId)); /** @var \Magento\Catalog\Model\Product $product */ $product = $this->objectManager->get(ProductRepositoryInterface::class)->getById($productId); $this->assertFalse($product->isObjectNew()); - $this->assertEquals(self::TEST_PRODUCT_NAME, $product->getName()); + $this->assertEquals($productName, $product->getName()); $this->assertEquals(self::TEST_PRODUCT_TYPE, $product->getTypeId()); $optionCollection = $product->getTypeInstance()->getConfigurableOptions($product); foreach ($optionCollection as $option) { foreach ($option as $optionData) { - $this->assertContains($optionData['sku'], $this->optionSkuList); + $this->assertContains($optionData['sku'], $optionSkuList); } } - $optionIdList = $resource->getProductsIdsBySkus($this->optionSkuList); + $optionIdList = $resource->getProductsIdsBySkus($optionSkuList); foreach ($optionIdList as $optionId) { $this->assertArrayHasKey($optionId, $product->getExtensionAttributes()->getConfigurableProductLinks()); } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable_12345.csv b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable_12345.csv new file mode 100644 index 0000000000000..02cfb46e920ca --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable_12345.csv @@ -0,0 +1,4 @@ +sku,store_view_code,attribute_set_code,product_type,name,description,short_description,weight,product_online,tax_class_name,visibility,price,url_key,display_product_options_in,map_price,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,configurable_variations,configurable_variation_labels,associated_skus +Configurable 1-Option 1,,Default,simple,Configurable 1-Option 1,,,,1,Taxable Goods,Not Visible Individually,10,configurable-1-option-1,Block after Info Column,,"attribute_with_option=Option Label,has_options=0,quantity_and_stock_status=In Stock,required_options=0,test_configurable=Option 1",99999,0,0,0,0,1,1,0,0,0,1,,1,1,0,0,1,0,0,0,1,,, +Configurable 1-Option 2,,Default,simple,Configurable 1-Option 2,,,,1,Taxable Goods,Not Visible Individually,10,configurable-1-option-2,Block after Info Column,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0,test_configurable=Option 2",99999,0,0,0,0,1,1,0,0,0,1,,1,1,0,0,1,0,0,0,1,,, +12345,,Default,configurable,12345,,,,1,Taxable Goods,"Catalog, Search",10,12345,Block after Info Column,,"has_options=1,quantity_and_stock_status=In Stock,required_options=0",0,0,0,0,0,1,1,0,0,0,1,,1,0,0,0,1,0,0,0,1,"sku=Configurable 1-Option 1,test_configurable=Option 1|sku=Configurable 1-Option 2,test_configurable=Option 2",test_configurable=test_configurable, diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345.php new file mode 100644 index 0000000000000..d2fd3bd6fccc2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345.php @@ -0,0 +1,133 @@ +reinitialize(); + +require __DIR__ . '/configurable_attribute.php'; + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = Bootstrap::getObjectManager() + ->create(ProductRepositoryInterface::class); + +/** @var $installer CategorySetup */ +$installer = Bootstrap::getObjectManager()->create(CategorySetup::class); + +/* Create simple products per each option value*/ +/** @var AttributeOptionInterface[] $options */ +$options = $attribute->getOptions(); + +$attributeValues = []; +$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default'); +$associatedProductIds = []; +$productIds = [30, 40]; +array_shift($options); //remove the first option which is empty + +foreach ($options as $option) { + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $productId = array_shift($productIds); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId($productId) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Option' . $option->getLabel()) + ->setSku('simple_' . $productId) + ->setPrice($productId) + ->setTestConfigurable($option->getValue()) + ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + + $product = $productRepository->save($product); + + /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */ + $stockItem = Bootstrap::getObjectManager()->create(\Magento\CatalogInventory\Model\Stock\Item::class); + $stockItem->load($productId, 'product_id'); + + if (!$stockItem->getProductId()) { + $stockItem->setProductId($productId); + } + $stockItem->setUseConfigManageStock(1); + $stockItem->setQty(1000); + $stockItem->setIsQtyDecimal(0); + $stockItem->setIsInStock(1); + $stockItem->save(); + + $attributeValues[] = [ + 'label' => 'test', + 'attribute_id' => $attribute->getId(), + 'value_index' => $option->getValue(), + ]; + $associatedProductIds[] = $product->getId(); +} + +/** @var $product Product */ +$product = Bootstrap::getObjectManager()->create(Product::class); + +/** @var Factory $optionsFactory */ +$optionsFactory = Bootstrap::getObjectManager()->create(Factory::class); + +$configurableAttributesData = [ + [ + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'label' => $attribute->getStoreLabel(), + 'position' => '0', + 'values' => $attributeValues, + ], +]; + +$configurableOptions = $optionsFactory->create($configurableAttributesData); + +$extensionConfigurableAttributes = $product->getExtensionAttributes(); +$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions); +$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds); + +$product->setExtensionAttributes($extensionConfigurableAttributes); + +// Remove any previously created product with the same id. +/** @var \Magento\Framework\Registry $registry */ +$registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +try { + $productToDelete = $productRepository->getById(11); + $productRepository->delete($productToDelete); + + /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */ + $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class); + $itemResource->getConnection()->delete( + $itemResource->getMainTable(), + 'product_id = ' . $productToDelete->getId() + ); +} catch (\Exception $e) { + // Nothing to remove +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +$product->setTypeId(Configurable::TYPE_CODE) + ->setId(11) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Product 12345') + ->setSku('12345') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345_rollback.php new file mode 100644 index 0000000000000..c40bd7692bbdc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345_rollback.php @@ -0,0 +1,35 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +foreach (['simple_30', 'simple_40', '12345'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + + $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class); + $stockStatus->load($product->getEntityId(), 'product_id'); + $stockStatus->delete(); + + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +require __DIR__ . '/configurable_attribute_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false);