From b25a34f3dab7fb228241156a328591c67a8bcbeb Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Tue, 10 Mar 2020 13:45:49 +0100 Subject: [PATCH 01/16] WIP: Fix for issue 12584 - save scoped bundle prices --- .../Magento/Bundle/Model/LinkManagement.php | 3 +++ .../Bundle/Model/Option/SaveAction.php | 11 ++++++++- app/code/Magento/Bundle/Model/Selection.php | 14 +++++++++++ .../Test/Unit/Model/LinkManagementTest.php | 24 ++++++++++++++----- app/code/Magento/Bundle/etc/events.xml | 3 +++ 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Bundle/Model/LinkManagement.php b/app/code/Magento/Bundle/Model/LinkManagement.php index 8c85c06c7342d..d1ddb3ce8d34d 100644 --- a/app/code/Magento/Bundle/Model/LinkManagement.php +++ b/app/code/Magento/Bundle/Model/LinkManagement.php @@ -209,6 +209,9 @@ protected function mapProductLinkToSelectionModel( if ($productLink->getIsDefault() !== null) { $selectionModel->setIsDefault($productLink->getIsDefault()); } + if ($productLink->getWebsiteId() !== null) { + $selectionModel->setWebsiteId($productLink->getWebsiteId()); + } return $selectionModel; } diff --git a/app/code/Magento/Bundle/Model/Option/SaveAction.php b/app/code/Magento/Bundle/Model/Option/SaveAction.php index 00c5b05d532f5..bf11a0f010b78 100644 --- a/app/code/Magento/Bundle/Model/Option/SaveAction.php +++ b/app/code/Magento/Bundle/Model/Option/SaveAction.php @@ -14,6 +14,7 @@ use Magento\Framework\Exception\CouldNotSaveException; use Magento\Bundle\Model\Product\Type; use Magento\Bundle\Api\ProductLinkManagementInterface; +use Magento\Store\Model\StoreManagerInterface; /** * Encapsulates logic for saving a bundle option, including coalescing the parent product's data. @@ -40,17 +41,24 @@ class SaveAction */ private $linkManagement; + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * @param Option $optionResource * @param MetadataPool $metadataPool * @param Type $type * @param ProductLinkManagementInterface $linkManagement + * @param StoreManagerInterface $storeManager */ public function __construct( Option $optionResource, MetadataPool $metadataPool, Type $type, - ProductLinkManagementInterface $linkManagement + ProductLinkManagementInterface $linkManagement, + StoreManagerInterface $storeManager ) { $this->optionResource = $optionResource; $this->metadataPool = $metadataPool; @@ -135,6 +143,7 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac if (is_array($option->getProductLinks())) { $productLinks = $option->getProductLinks(); foreach ($productLinks as $productLink) { + $productLink->setWebsiteId($this->storeManager->getStore($product->getStoreId())->getWebsiteId()); if (!$productLink->getId() && !$productLink->getSelectionId()) { $linksToAdd[] = $productLink; } else { diff --git a/app/code/Magento/Bundle/Model/Selection.php b/app/code/Magento/Bundle/Model/Selection.php index f8e3d05fd9809..1160a3cc0bec0 100644 --- a/app/code/Magento/Bundle/Model/Selection.php +++ b/app/code/Magento/Bundle/Model/Selection.php @@ -20,6 +20,8 @@ * @method \Magento\Bundle\Model\Selection setPosition(int $value) * @method int getIsDefault() * @method \Magento\Bundle\Model\Selection setIsDefault(int $value) + * @method int getWebsiteId() + * @method \Magento\Bundle\Model\Selection setWebsiteId(int $value) * @method int getSelectionPriceType() * @method \Magento\Bundle\Model\Selection setSelectionPriceType(int $value) * @method float getSelectionPriceValue() @@ -71,6 +73,15 @@ protected function _construct() parent::_construct(); } + public function beforeSave() + { + if (!$this->_catalogData->isPriceGlobal() && $this->getWebsiteId()) { + $this->setData('website_selection_price_value', $this->getSelectionPriceValue()); + $this->setSelectionPriceValue($this->getOrigData('selection_price_value')); + } + parent::beforeSave(); + } + /** * Processing object before save data * @@ -79,6 +90,9 @@ protected function _construct() public function afterSave() { if (!$this->_catalogData->isPriceGlobal() && $this->getWebsiteId()) { + if (null !== $this->getData('website_selection_price_value')) { + $this->setSelectionPriceValue($this->getData('website_selection_price_value')); + } $this->getResource()->saveSelectionPrice($this); if (!$this->getDefaultPriceScope()) { diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index ccc8c52d5022f..eeac60eea556b 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -468,13 +468,15 @@ public function testAddChildProductAlreadyExistsInOption() */ public function testAddChildCouldNotSave() { + $websiteId = 100; $productLink = $this->getMockBuilder(\Magento\Bundle\Api\Data\LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebsiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getOptionId')->will($this->returnValue(1)); $productLink->expects($this->any())->method('getSelectionId')->will($this->returnValue(1)); + $productLink->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId)); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(\Magento\Catalog\Model\Product::class); @@ -541,13 +543,15 @@ function () { public function testAddChild() { + $websiteId = 100; $productLink = $this->getMockBuilder(\Magento\Bundle\Api\Data\LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebsiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getOptionId')->will($this->returnValue(1)); $productLink->expects($this->any())->method('getSelectionId')->will($this->returnValue(1)); + $productLink->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId)); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(\Magento\Catalog\Model\Product::class); @@ -620,9 +624,10 @@ public function testSaveChild() $linkProductId = 45; $parentProductId = 32; $bundleProductSku = 'bundleProductSku'; + $websiteId = 100; $productLink = $this->getMockBuilder(\Magento\Bundle\Api\Data\LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebsiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); @@ -636,6 +641,7 @@ public function testSaveChild() ->will($this->returnValue($canChangeQuantity)); $productLink->expects($this->any())->method('getIsDefault')->will($this->returnValue($isDefault)); $productLink->expects($this->any())->method('getSelectionId')->will($this->returnValue($optionId)); + $productLink->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId)); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(\Magento\Catalog\Model\Product::class); @@ -677,7 +683,8 @@ public function testSaveChild() 'setSelectionPriceType', 'setSelectionPriceValue', 'setSelectionCanChangeQty', - 'setIsDefault' + 'setIsDefault', + 'setWebsiteId' ]); $selection->expects($this->once())->method('save'); $selection->expects($this->once())->method('load')->with($id)->will($this->returnSelf()); @@ -691,6 +698,7 @@ public function testSaveChild() $selection->expects($this->once())->method('setSelectionPriceValue')->with($price); $selection->expects($this->once())->method('setSelectionCanChangeQty')->with($canChangeQuantity); $selection->expects($this->once())->method('setIsDefault')->with($isDefault); + $selection->expects($this->once())->method('setWebsiteId')->with($websiteId); $this->bundleSelectionMock->expects($this->once())->method('create')->will($this->returnValue($selection)); $this->assertTrue($this->model->saveChild($bundleProductSku, $productLink)); @@ -704,14 +712,16 @@ public function testSaveChildFailedToSave() $id = 12; $linkProductId = 45; $parentProductId = 32; + $websiteId = 200; $productLink = $this->getMockBuilder(\Magento\Bundle\Api\Data\LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebsiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getId')->will($this->returnValue($id)); $productLink->expects($this->any())->method('getSelectionId')->will($this->returnValue(1)); + $productLink->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId)); $bundleProductSku = 'bundleProductSku'; $productMock = $this->createMock(\Magento\Catalog\Model\Product::class); @@ -751,13 +761,15 @@ public function testSaveChildFailedToSave() 'setSelectionPriceType', 'setSelectionPriceValue', 'setSelectionCanChangeQty', - 'setIsDefault' + 'setIsDefault', + 'setWebsiteId' ]); $mockException = $this->createMock(\Exception::class); $selection->expects($this->once())->method('save')->will($this->throwException($mockException)); $selection->expects($this->once())->method('load')->with($id)->will($this->returnSelf()); $selection->expects($this->any())->method('getId')->will($this->returnValue($id)); $selection->expects($this->once())->method('setProductId')->with($linkProductId); + $selection->expects($this->once())->method('setWebsiteId')->with($websiteId); $this->bundleSelectionMock->expects($this->once())->method('create')->will($this->returnValue($selection)); $this->model->saveChild($bundleProductSku, $productLink); diff --git a/app/code/Magento/Bundle/etc/events.xml b/app/code/Magento/Bundle/etc/events.xml index 6c855db2d323b..b2d43a808860d 100644 --- a/app/code/Magento/Bundle/etc/events.xml +++ b/app/code/Magento/Bundle/etc/events.xml @@ -18,4 +18,7 @@ + + + From a59b0e8cb5b1f91ed835352f624a5e965cefb5b8 Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Tue, 17 Mar 2020 12:57:47 +0100 Subject: [PATCH 02/16] Set storemanager prop. --- app/code/Magento/Bundle/Model/Option/SaveAction.php | 1 + app/code/Magento/Bundle/Model/Selection.php | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Bundle/Model/Option/SaveAction.php b/app/code/Magento/Bundle/Model/Option/SaveAction.php index bf11a0f010b78..806a22412f00f 100644 --- a/app/code/Magento/Bundle/Model/Option/SaveAction.php +++ b/app/code/Magento/Bundle/Model/Option/SaveAction.php @@ -64,6 +64,7 @@ public function __construct( $this->metadataPool = $metadataPool; $this->type = $type; $this->linkManagement = $linkManagement; + $this->storeManager = $storeManager; } /** diff --git a/app/code/Magento/Bundle/Model/Selection.php b/app/code/Magento/Bundle/Model/Selection.php index 1160a3cc0bec0..57b27703bf488 100644 --- a/app/code/Magento/Bundle/Model/Selection.php +++ b/app/code/Magento/Bundle/Model/Selection.php @@ -76,7 +76,7 @@ protected function _construct() public function beforeSave() { if (!$this->_catalogData->isPriceGlobal() && $this->getWebsiteId()) { - $this->setData('website_selection_price_value', $this->getSelectionPriceValue()); + $this->setData('tmp_selection_price_value', $this->getSelectionPriceValue()); $this->setSelectionPriceValue($this->getOrigData('selection_price_value')); } parent::beforeSave(); @@ -90,8 +90,8 @@ public function beforeSave() public function afterSave() { if (!$this->_catalogData->isPriceGlobal() && $this->getWebsiteId()) { - if (null !== $this->getData('website_selection_price_value')) { - $this->setSelectionPriceValue($this->getData('website_selection_price_value')); + if (null !== $this->getData('tmp_selection_price_value')) { + $this->setSelectionPriceValue($this->getData('tmp_selection_price_value')); } $this->getResource()->saveSelectionPrice($this); From 8cca552dc880227a1a91d4633bebc8d66c50a57d Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Tue, 17 Mar 2020 15:57:19 +0100 Subject: [PATCH 03/16] Add missing doc block for beforeSave. --- app/code/Magento/Bundle/Model/Selection.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Model/Selection.php b/app/code/Magento/Bundle/Model/Selection.php index 57b27703bf488..c197d758340f1 100644 --- a/app/code/Magento/Bundle/Model/Selection.php +++ b/app/code/Magento/Bundle/Model/Selection.php @@ -73,6 +73,11 @@ protected function _construct() parent::_construct(); } + /** + * Processin object before save data + * + * @return void + */ public function beforeSave() { if (!$this->_catalogData->isPriceGlobal() && $this->getWebsiteId()) { @@ -83,7 +88,7 @@ public function beforeSave() } /** - * Processing object before save data + * Processing object after save data * * @return $this */ From 49c261ebdbfa3932b4dcac015ffe42e681dcb136 Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Wed, 18 Mar 2020 09:47:18 +0100 Subject: [PATCH 04/16] Fixed typo in docblock --- app/code/Magento/Bundle/Model/Selection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Model/Selection.php b/app/code/Magento/Bundle/Model/Selection.php index c197d758340f1..a7e20511ecb54 100644 --- a/app/code/Magento/Bundle/Model/Selection.php +++ b/app/code/Magento/Bundle/Model/Selection.php @@ -74,7 +74,7 @@ protected function _construct() } /** - * Processin object before save data + * Processing object before save data * * @return void */ From 659beb2fd940c2435d5f1b75fdefe06ad4c13871 Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Wed, 18 Mar 2020 16:19:50 +0100 Subject: [PATCH 05/16] Fixes for failed static tests in Bundle module. --- .../Magento/Bundle/Model/LinkManagement.php | 24 +++++++++++++++---- .../Bundle/Model/Option/SaveAction.php | 2 +- app/code/Magento/Bundle/Model/Selection.php | 2 +- .../Test/Unit/Model/LinkManagementTest.php | 4 ++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Bundle/Model/LinkManagement.php b/app/code/Magento/Bundle/Model/LinkManagement.php index d1ddb3ce8d34d..e79323e8b1584 100644 --- a/app/code/Magento/Bundle/Model/LinkManagement.php +++ b/app/code/Magento/Bundle/Model/LinkManagement.php @@ -54,6 +54,11 @@ class LinkManagement implements \Magento\Bundle\Api\ProductLinkManagementInterfa */ private $metadataPool; + /** + * @var \Magento\Store\Model\StoreManagerInterface + */ + private $storeManager; + /** * @param ProductRepositoryInterface $productRepository * @param \Magento\Bundle\Api\Data\LinkInterfaceFactory $linkFactory @@ -82,7 +87,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getChildren($productSku, $optionId = null) { @@ -105,7 +110,7 @@ public function getChildren($productSku, $optionId = null) } /** - * {@inheritdoc} + * @inheritdoc */ public function addChildByProductSku($sku, $optionId, \Magento\Bundle\Api\Data\LinkInterface $linkedProduct) { @@ -115,7 +120,8 @@ public function addChildByProductSku($sku, $optionId, \Magento\Bundle\Api\Data\L } /** - * {@inheritdoc} + * @inheritdoc + * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -169,6 +175,8 @@ public function saveChild( } /** + * Map data from the product link object to the new selection model + * * @param \Magento\Bundle\Model\Selection $selectionModel * @param \Magento\Bundle\Api\Data\LinkInterface $productLink * @param string $linkedProductId @@ -217,7 +225,8 @@ protected function mapProductLinkToSelectionModel( } /** - * {@inheritdoc} + * @inheritdoc + * * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function addChild( @@ -297,7 +306,7 @@ public function addChild( } /** - * {@inheritdoc} + * @inheritdoc */ public function removeChild($sku, $optionId, $childSku) { @@ -336,6 +345,8 @@ public function removeChild($sku, $optionId, $childSku) } /** + * Build new Link object from the product and selection + * * @param \Magento\Catalog\Model\Product $selection * @param \Magento\Catalog\Model\Product $product * @return \Magento\Bundle\Api\Data\LinkInterface @@ -367,6 +378,8 @@ private function buildLink(\Magento\Catalog\Model\Product $selection, \Magento\C } /** + * Retrieve bundle options with selections + * * @param \Magento\Catalog\Api\Data\ProductInterface $product * @return \Magento\Bundle\Api\Data\OptionInterface[] */ @@ -392,6 +405,7 @@ private function getOptions(\Magento\Catalog\Api\Data\ProductInterface $product) /** * Get MetadataPool instance + * * @return MetadataPool */ private function getMetadataPool() diff --git a/app/code/Magento/Bundle/Model/Option/SaveAction.php b/app/code/Magento/Bundle/Model/Option/SaveAction.php index 806a22412f00f..67dcf9e8838e5 100644 --- a/app/code/Magento/Bundle/Model/Option/SaveAction.php +++ b/app/code/Magento/Bundle/Model/Option/SaveAction.php @@ -102,7 +102,7 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option) } } else { if (!$existingOption->getOptionId()) { - throw new NoSuchEntityException( + throw new \Magento\Framework\Exception\NoSuchEntityException( __("The option that was requested doesn't exist. Verify the entity and try again.") ); } diff --git a/app/code/Magento/Bundle/Model/Selection.php b/app/code/Magento/Bundle/Model/Selection.php index a7e20511ecb54..3137f723e57c0 100644 --- a/app/code/Magento/Bundle/Model/Selection.php +++ b/app/code/Magento/Bundle/Model/Selection.php @@ -105,6 +105,6 @@ public function afterSave() $this->unsSelectionPriceType(); } } - parent::afterSave(); + return parent::afterSave(); } } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index eeac60eea556b..285c54622b830 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -11,7 +11,7 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** - * Class LinkManagementTest + * Unit Test for Link Management Model * * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -121,7 +121,7 @@ protected function setUp() ->setMethods(['get']) ->disableOriginalConstructor() ->getMock(); - $this->productType = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type\Interceptor::class) + $this->productType = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class) ->setMethods(['getOptionsCollection', 'setStoreFilter', 'getSelectionsCollection', 'getOptionsIds']) ->disableOriginalConstructor() ->getMock(); From fd40a7b2eb3d3cabc7b59c148e8048544f1230d0 Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Fri, 10 Jul 2020 15:41:52 +0200 Subject: [PATCH 06/16] Avoid duplicate keys when updating from select --- .../Model/ResourceModel/Indexer/Price.php | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php index 96d68d7e74117..7b26f6e76ca2a 100644 --- a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php +++ b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php @@ -455,6 +455,42 @@ private function getBaseBundleSelectionPriceSelect(): Select return $select; } + /** + * Get base select for bundle selection price update + * + * @return Select + * @throws \Exception + */ + private function getBaseBundleSelectionPriceUpdateSelect(): Select + { + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); + $linkField = $metadata->getLinkField(); + $bundleSelectionTable = $this->getBundleSelectionTable(); + + $select = $this->getConnection()->select() + ->join( + ['i' => $this->getBundlePriceTable()], + "i.entity_id = $bundleSelectionTable.entity_id + AND i.customer_group_id = $bundleSelectionTable.customer_group_id + AND i.website_id = $bundleSelectionTable.website_id", + [] + )->join( + ['parent_product' => $this->getTable('catalog_product_entity')], + 'parent_product.entity_id = i.entity_id', + [] + )->join( + ['bo' => $this->getTable('catalog_product_bundle_option')], + "bo.parent_id = parent_product.$linkField AND bo.option_id = $bundleSelectionTable.option_id", + ['option_id'] + )->join( + ['bs' => $this->getTable('catalog_product_bundle_selection')], + "bs.option_id = bo.option_id AND bs.selection_id = $bundleSelectionTable.selection_id", + ['selection_id'] + ); + + return $select; + } + /** * Apply selections price for fixed bundles * @@ -498,7 +534,7 @@ private function applyFixedBundleSelectionPrice() ] ); - $select = $this->getBaseBundleSelectionPriceSelect(); + $select = $this->getBaseBundleSelectionPriceUpdateSelect(); $select->joinInner( ['bsp' => $this->getTable('catalog_product_bundle_selection_price')], 'bs.selection_id = bsp.selection_id AND bsp.website_id = i.website_id', From 56ef44b3a8a8ef927a0853af8f84016f57f3ac71 Mon Sep 17 00:00:00 2001 From: Joel Rainwater Date: Fri, 21 Aug 2020 14:33:25 +0200 Subject: [PATCH 07/16] Cleanup changes from PR #26397 --- app/code/Magento/Bundle/Model/LinkManagement.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/app/code/Magento/Bundle/Model/LinkManagement.php b/app/code/Magento/Bundle/Model/LinkManagement.php index efeddca561b13..234ec7eb1acdc 100644 --- a/app/code/Magento/Bundle/Model/LinkManagement.php +++ b/app/code/Magento/Bundle/Model/LinkManagement.php @@ -421,17 +421,4 @@ private function getOptions(ProductInterface $product) return $optionCollection->appendSelections($selectionCollection, true); } - - /** - * Get MetadataPool instance - * - * @return MetadataPool - */ - private function getMetadataPool() - { - if (!$this->metadataPool) { - $this->metadataPool = ObjectManager::getInstance()->get(MetadataPool::class); - } - return $this->metadataPool; - } } From 9f622eef3737e8f8ac34d1448d0f0e9facf736c8 Mon Sep 17 00:00:00 2001 From: engcom-Echo Date: Wed, 16 Sep 2020 14:45:33 +0300 Subject: [PATCH 08/16] fix unit, static tests --- .../Test/Unit/Model/LinkManagementTest.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index 3e0a4c825a425..12e50a304a55c 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -533,12 +533,13 @@ public function testAddChildCouldNotSave() $this->expectException(CouldNotSaveException::class); $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebSiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); + $productLink->method('getWebSiteId')->willReturn(100); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -610,12 +611,13 @@ static function () { public function testAddChild() { $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebSiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); + $productLink->method('getWebSiteId')->willReturn(100); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -689,7 +691,7 @@ public function testSaveChild() $websiteId = 100; $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebSiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); @@ -703,6 +705,7 @@ public function testSaveChild() ->willReturn($canChangeQuantity); $productLink->method('getIsDefault')->willReturn($isDefault); $productLink->method('getSelectionId')->willReturn($optionId); + $productLink->method('getWebSiteId')->willReturn($websiteId); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -741,7 +744,8 @@ public function testSaveChild() 'setSelectionPriceType', 'setSelectionPriceValue', 'setSelectionCanChangeQty', - 'setIsDefault' + 'setIsDefault', + 'setWebsiteId' ] ) ->onlyMethods(['save', 'getId', 'load']) @@ -775,12 +779,14 @@ public function testSaveChildFailedToSave() $websiteId = 200; $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebsiteId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getId')->willReturn($id); $productLink->method('getSelectionId')->willReturn(1); + $productLink->method('getWebsiteId')->willReturn($websiteId); + $bundleProductSku = 'bundleProductSku'; $productMock = $this->createMock(Product::class); From 64db19a685fcce189f3373ca65031b53653fb2e2 Mon Sep 17 00:00:00 2001 From: engcom-Echo Date: Wed, 16 Sep 2020 21:37:58 +0300 Subject: [PATCH 09/16] refactoring SaveAction.php, add MFTF test --- .../Bundle/Model/Option/SaveAction.php | 23 +++-- .../Bundle/Test/Mftf/Data/BundleLinkData.xml | 9 ++ ...ductTwoWebsiteDifferentPriceOptionTest.xml | 95 +++++++++++++++++++ 3 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml diff --git a/app/code/Magento/Bundle/Model/Option/SaveAction.php b/app/code/Magento/Bundle/Model/Option/SaveAction.php index 67dcf9e8838e5..3f7bd0de2a372 100644 --- a/app/code/Magento/Bundle/Model/Option/SaveAction.php +++ b/app/code/Magento/Bundle/Model/Option/SaveAction.php @@ -7,9 +7,11 @@ namespace Magento\Bundle\Model\Option; +use Magento\Bundle\Api\Data\LinkInterface; use Magento\Bundle\Api\Data\OptionInterface; use Magento\Bundle\Model\ResourceModel\Option; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\App\ObjectManager; use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Bundle\Model\Product\Type; @@ -51,20 +53,21 @@ class SaveAction * @param MetadataPool $metadataPool * @param Type $type * @param ProductLinkManagementInterface $linkManagement - * @param StoreManagerInterface $storeManager + * @param StoreManagerInterface|null $storeManager */ public function __construct( Option $optionResource, MetadataPool $metadataPool, Type $type, ProductLinkManagementInterface $linkManagement, - StoreManagerInterface $storeManager + ?StoreManagerInterface $storeManager = null ) { $this->optionResource = $optionResource; $this->metadataPool = $metadataPool; $this->type = $type; $this->linkManagement = $linkManagement; - $this->storeManager = $storeManager; + $this->storeManager = $storeManager + ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); } /** @@ -78,7 +81,7 @@ public function __construct( */ public function save(ProductInterface $bundleProduct, OptionInterface $option) { - $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); $option->setStoreId($bundleProduct->getStoreId()); $parentId = $bundleProduct->getData($metadata->getLinkField()); @@ -117,7 +120,7 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option) throw new CouldNotSaveException(__("The option couldn't be saved."), $e); } - /** @var \Magento\Bundle\Api\Data\LinkInterface $linkedProduct */ + /** @var LinkInterface $linkedProduct */ foreach ($linksToAdd as $linkedProduct) { $this->linkManagement->addChild($bundleProduct, $option->getOptionId(), $linkedProduct); } @@ -130,8 +133,8 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option) /** * Update option selections * - * @param \Magento\Catalog\Api\Data\ProductInterface $product - * @param \Magento\Bundle\Api\Data\OptionInterface $option + * @param ProductInterface $product + * @param OptionInterface $option * @return void */ private function updateOptionSelection(ProductInterface $product, OptionInterface $option) @@ -151,7 +154,7 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac $linksToUpdate[] = $productLink; } } - /** @var \Magento\Bundle\Api\Data\LinkInterface[] $linksToDelete */ + /** @var LinkInterface[] $linksToDelete */ $linksToDelete = $this->compareLinks($existingLinks, $linksToUpdate); } foreach ($linksToUpdate as $linkedProduct) { @@ -172,8 +175,8 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac /** * Compute the difference between given arrays. * - * @param \Magento\Bundle\Api\Data\LinkInterface[] $firstArray - * @param \Magento\Bundle\Api\Data\LinkInterface[] $secondArray + * @param LinkInterface[] $firstArray + * @param LinkInterface[] $secondArray * * @return array */ diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml index 60d11345731c1..75ab4393e0475 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml @@ -17,4 +17,13 @@ 1 1 + + + + 1 + 1 + 30 + 0 + 1 + diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml new file mode 100644 index 0000000000000..6a74c63aa12da --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml @@ -0,0 +1,95 @@ + + + + + + + + <stories value="Github issue: #12584 Bundle Item price cannot differ per website"/> + <description value="Verify bundle item price different websites. Change bundle item price on second website."/> + <features value="Bundle"/> + <group value="bundle"/> + </annotations> + <before> + <magentoCLI command="config:set {{WebsiteCatalogPriceScopeConfigData.path}} {{WebsiteCatalogPriceScopeConfigData.value}}" stepKey="setPriceScopeWebsite"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="logInAsAdmin"/> + + <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createWebsite"> + <argument name="newWebsiteName" value="{{customWebsite.name}}"/> + <argument name="websiteCode" value="{{customWebsite.code}}"/> + </actionGroup> + <actionGroup ref="CreateCustomStoreActionGroup" stepKey="createCustomStoreGroup"> + <argument name="website" value="{{customWebsite.name}}"/> + <argument name="store" value="{{customStoreGroup.name}}"/> + <argument name="rootCategory" value="Default Category"/> + </actionGroup> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createCustomStoreView"> + <argument name="StoreGroup" value="customStoreGroup"/> + <argument name="customStore" value="customStore"/> + </actionGroup> + + <createData entity="SimpleProduct2" stepKey="simpleProduct"/> + <createData entity="ApiFixedBundleProduct" stepKey="createBundleProduct" /> + <createData entity="CheckboxOption" stepKey="createBundleOption"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLinkFixed" stepKey="linkOptionToProduct"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption"/> + <requiredEntity createDataKey="simpleProduct"/> + </createData> + </before> + <after> + <magentoCLI command="config:set {{GlobalCatalogPriceScopeConfigData.path}} {{GlobalCatalogPriceScopeConfigData.value}}" stepKey="setPriceScopeGlobal"/> + + <deleteData createDataKey="simpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createBundleProduct" stepKey="deleteBundleProduct"/> + + <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteWebsite"> + <argument name="websiteName" value="{{customWebsite.name}}"/> + </actionGroup> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> + <argument name="indices" value=""/> + </actionGroup> + <actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanFullPageCache"> + <argument name="tags" value="config full_page"/> + </actionGroup> + </after> + + <actionGroup ref="NavigateToCreatedProductEditPageActionGroup" stepKey="openEditBundleProduct"> + <argument name="product" value="$$createBundleProduct$$"/> + </actionGroup> + + <actionGroup ref="AdminAssignProductInWebsiteActionGroup" stepKey="selectProductInWebsites"> + <argument name="website" value="{{customWebsite.name}}"/> + </actionGroup> + <actionGroup ref="SaveProductFormActionGroup" stepKey="clickSaveButton"/> + <actionGroup ref="SwitchToTheNewStoreViewActionGroup" stepKey="SwitchNewStoreView"> + <argument name="storeViewName" value="{{customStore.name}}"/> + </actionGroup> + + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYPrice('0', '0')}}" userInput="100" stepKey="fillBundleOption1Price"/> + + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveNewPrice"/> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductPage"> + <argument name="productUrl" value="$$createBundleProduct.custom_attributes[url_key]$$"/> + </actionGroup> + + <click selector="{{StorefrontBundledSection.addToCart}}" stepKey="clickCustomizeAndAddToCart"/> + + <grabTextFrom selector="{{StorefrontBundledSection.bundleProductsPrice}}" stepKey="grabPriceText"/> + <assertEquals stepKey="assertPriceText"> + <expectedResult type="string">$31.23</expectedResult> + <actualResult type="variable">$grabPriceText</actualResult> + </assertEquals> + + </test> +</tests> From ed0f987dc4ee5b34b7424d278783df297de982bf Mon Sep 17 00:00:00 2001 From: engcom-Echo <engcom-vendorworker-echo@adobe.com> Date: Thu, 17 Sep 2020 18:32:14 +0300 Subject: [PATCH 10/16] minor fix. added required annotations --- ...frontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml index 6a74c63aa12da..5fdce3fb555c8 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductTwoWebsiteDifferentPriceOptionTest.xml @@ -14,6 +14,7 @@ <stories value="Github issue: #12584 Bundle Item price cannot differ per website"/> <description value="Verify bundle item price different websites. Change bundle item price on second website."/> <features value="Bundle"/> + <severity value="MAJOR"/> <group value="bundle"/> </annotations> <before> From ac37ae1cf1e118fe771944b0680dcde017f0ea3e Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <engcom-vendorworker-foxtrot@adobe.com> Date: Thu, 19 Nov 2020 10:49:00 +0200 Subject: [PATCH 11/16] magento/magento2#12584: Bundle Item price cannot differ per website. --- .../Magento/Bundle/Model/LinkManagement.php | 68 ++++++++++++++++--- .../Bundle/Model/Option/SaveAction.php | 4 +- .../Test/Unit/Model/LinkManagementTest.php | 31 +++++++-- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Bundle/Model/LinkManagement.php b/app/code/Magento/Bundle/Model/LinkManagement.php index 234ec7eb1acdc..ca34c0e5423fb 100644 --- a/app/code/Magento/Bundle/Model/LinkManagement.php +++ b/app/code/Magento/Bundle/Model/LinkManagement.php @@ -19,9 +19,9 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product; use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\InputException; -use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Model\StoreManagerInterface; @@ -174,11 +174,12 @@ public function saveChild( ); } $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); - $selectionModel = $this->mapProductLinkToSelectionModel( + $selectionModel = $this->mapProductLinkToBundleSelectionModel( $selectionModel, $linkedProduct, - $linkProductModel->getId(), - $product->getData($linkField) + $product, + (int)$linkProductModel->getId(), + $linkField ); try { @@ -202,6 +203,7 @@ public function saveChild( * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + * @deprecated use mapProductLinkToBundleSelectionModel */ protected function mapProductLinkToSelectionModel( Selection $selectionModel, @@ -235,9 +237,55 @@ protected function mapProductLinkToSelectionModel( if ($productLink->getIsDefault() !== null) { $selectionModel->setIsDefault($productLink->getIsDefault()); } - if ($productLink->getWebsiteId() !== null) { - $selectionModel->setWebsiteId($productLink->getWebsiteId()); + + return $selectionModel; + } + + /** + * Fill selection model with product link data. + * + * @param Selection $selectionModel + * @param LinkInterface $productLink + * @param ProductInterface $parentProduct + * @param int $linkedProductId + * @param string $linkField + * @return Selection + * @throws NoSuchEntityException + */ + private function mapProductLinkToBundleSelectionModel( + Selection $selectionModel, + LinkInterface $productLink, + ProductInterface $parentProduct, + int $linkedProductId, + string $linkField + ): Selection { + $selectionModel->setProductId($linkedProductId); + $selectionModel->setParentProductId($parentProduct->getData($linkField)); + if ($productLink->getSelectionId() !== null) { + $selectionModel->setSelectionId($productLink->getSelectionId()); + } + if ($productLink->getOptionId() !== null) { + $selectionModel->setOptionId($productLink->getOptionId()); } + if ($productLink->getPosition() !== null) { + $selectionModel->setPosition($productLink->getPosition()); + } + if ($productLink->getQty() !== null) { + $selectionModel->setSelectionQty($productLink->getQty()); + } + if ($productLink->getPriceType() !== null) { + $selectionModel->setSelectionPriceType($productLink->getPriceType()); + } + if ($productLink->getPrice() !== null) { + $selectionModel->setSelectionPriceValue($productLink->getPrice()); + } + if ($productLink->getCanChangeQuantity() !== null) { + $selectionModel->setSelectionCanChangeQty($productLink->getCanChangeQuantity()); + } + if ($productLink->getIsDefault() !== null) { + $selectionModel->setIsDefault($productLink->getIsDefault()); + } + $selectionModel->setWebsiteId((int)$this->storeManager->getStore($parentProduct->getStoreId())->getWebsiteId()); return $selectionModel; } @@ -305,12 +353,14 @@ public function addChild( } $selectionModel = $this->bundleSelection->create(); - $selectionModel = $this->mapProductLinkToSelectionModel( + $selectionModel = $this->mapProductLinkToBundleSelectionModel( $selectionModel, $linkedProduct, - $linkProductModel->getEntityId(), - $product->getData($linkField) + $product, + (int)$linkProductModel->getEntityId(), + $linkField ); + $selectionModel->setOptionId($optionId); try { diff --git a/app/code/Magento/Bundle/Model/Option/SaveAction.php b/app/code/Magento/Bundle/Model/Option/SaveAction.php index 3f7bd0de2a372..176484d8ccbcf 100644 --- a/app/code/Magento/Bundle/Model/Option/SaveAction.php +++ b/app/code/Magento/Bundle/Model/Option/SaveAction.php @@ -16,6 +16,7 @@ use Magento\Framework\Exception\CouldNotSaveException; use Magento\Bundle\Model\Product\Type; use Magento\Bundle\Api\ProductLinkManagementInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Model\StoreManagerInterface; /** @@ -105,7 +106,7 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option) } } else { if (!$existingOption->getOptionId()) { - throw new \Magento\Framework\Exception\NoSuchEntityException( + throw new NoSuchEntityException( __("The option that was requested doesn't exist. Verify the entity and try again.") ); } @@ -147,7 +148,6 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac if (is_array($option->getProductLinks())) { $productLinks = $option->getProductLinks(); foreach ($productLinks as $productLink) { - $productLink->setWebsiteId($this->storeManager->getStore($product->getStoreId())->getWebsiteId()); if (!$productLink->getId() && !$productLink->getSelectionId()) { $linksToAdd[] = $productLink; } else { diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index 12e50a304a55c..0d4a6f36d9ec9 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -31,6 +31,7 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Api\Data\WebsiteInterface; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; use PHPUnit\Framework\MockObject\MockObject; @@ -139,6 +140,11 @@ class LinkManagementTest extends TestCase */ private $linkField = 'product_id'; + /** + * @var WebsiteInterface|MockObject + */ + private $websiteMock; + /** * @inheritDoc */ @@ -203,6 +209,9 @@ protected function setUp(): void $this->dataObjectHelperMock = $this->getMockBuilder(DataObjectHelper::class) ->disableOriginalConstructor() ->getMock(); + + $this->websiteMock = $this->getMockForAbstractClass( WebsiteInterface::class); + $this->model = $helper->getObject( LinkManagement::class, [ @@ -539,7 +548,9 @@ public function testAddChildCouldNotSave() $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); - $productLink->method('getWebSiteId')->willReturn(100); + $store = $this->createMock(Store::class); + $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); + $store->expects($this->once())->method('getWebsiteId')->willReturn(100); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -617,7 +628,9 @@ public function testAddChild() $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); - $productLink->method('getWebSiteId')->willReturn(100); + $store = $this->createMock(Store::class); + $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); + $store->expects($this->once())->method('getWebsiteId')->willReturn(100); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -705,7 +718,9 @@ public function testSaveChild() ->willReturn($canChangeQuantity); $productLink->method('getIsDefault')->willReturn($isDefault); $productLink->method('getSelectionId')->willReturn($optionId); - $productLink->method('getWebSiteId')->willReturn($websiteId); + $store = $this->createMock(Store::class); + $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); + $store->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -785,16 +800,22 @@ public function testSaveChildFailedToSave() $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getId')->willReturn($id); $productLink->method('getSelectionId')->willReturn(1); - $productLink->method('getWebsiteId')->willReturn($websiteId); + $store = $this->createMock(Store::class); + $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); + $store->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); $bundleProductSku = 'bundleProductSku'; - + $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); $productMock->expects($this->once()) ->method('getTypeId') ->willReturn(Type::TYPE_BUNDLE); $productMock->method('getId') ->willReturn($parentProductId); + $productMock + ->method('getData') + ->with($this->linkField) + ->willReturn($parentProductId); $linkedProductMock = $this->createMock(Product::class); $linkedProductMock->method('getId')->willReturn($linkProductId); From 975c0c143b7c9e18164387fff5d81ecc61266356 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <engcom-vendorworker-foxtrot@adobe.com> Date: Thu, 19 Nov 2020 14:52:30 +0200 Subject: [PATCH 12/16] magento/magento2#12584: Bundle Item price cannot differ per website. --- .../Test/Unit/Model/LinkManagementTest.php | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index 0d4a6f36d9ec9..5ced384a66a88 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -542,15 +542,12 @@ public function testAddChildCouldNotSave() $this->expectException(CouldNotSaveException::class); $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebSiteId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); - $store = $this->createMock(Store::class); - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); - $store->expects($this->once())->method('getWebsiteId')->willReturn(100); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -622,15 +619,12 @@ static function () { public function testAddChild() { $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebSiteId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); - $store = $this->createMock(Store::class); - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); - $store->expects($this->once())->method('getWebsiteId')->willReturn(100); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -701,10 +695,9 @@ public function testSaveChild() $linkProductId = 45; $parentProductId = 32; $bundleProductSku = 'bundleProductSku'; - $websiteId = 100; $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebSiteId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); @@ -718,9 +711,6 @@ public function testSaveChild() ->willReturn($canChangeQuantity); $productLink->method('getIsDefault')->willReturn($isDefault); $productLink->method('getSelectionId')->willReturn($optionId); - $store = $this->createMock(Store::class); - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); - $store->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); @@ -760,7 +750,6 @@ public function testSaveChild() 'setSelectionPriceValue', 'setSelectionCanChangeQty', 'setIsDefault', - 'setWebsiteId' ] ) ->onlyMethods(['save', 'getId', 'load']) @@ -778,7 +767,6 @@ public function testSaveChild() $selection->expects($this->once())->method('setSelectionPriceValue')->with($price); $selection->expects($this->once())->method('setSelectionCanChangeQty')->with($canChangeQuantity); $selection->expects($this->once())->method('setIsDefault')->with($isDefault); - $selection->expects($this->once())->method('setWebsiteId')->with($websiteId); $this->bundleSelectionMock->expects($this->once())->method('create')->willReturn($selection); $this->assertTrue($this->model->saveChild($bundleProductSku, $productLink)); @@ -791,18 +779,14 @@ public function testSaveChildFailedToSave() $id = 12; $linkProductId = 45; $parentProductId = 32; - $websiteId = 200; $productLink = $this->getMockBuilder(LinkInterface::class) - ->setMethods(['getSku', 'getOptionId', 'getSelectionId', 'getWebsiteId']) + ->setMethods(['getSku', 'getOptionId', 'getSelectionId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $productLink->method('getSku')->willReturn('linked_product_sku'); $productLink->method('getId')->willReturn($id); $productLink->method('getSelectionId')->willReturn(1); - $store = $this->createMock(Store::class); - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($store); - $store->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); $bundleProductSku = 'bundleProductSku'; $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); From 605fb88ab4574d210b0bececb0f3708647eb793d Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <engcom-vendorworker-foxtrot@adobe.com> Date: Tue, 12 Jan 2021 18:59:51 +0200 Subject: [PATCH 13/16] magento/magento2#29549: Scheduled price rule time zone correction - refactoring. --- app/code/Magento/Bundle/Model/Option/SaveAction.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/code/Magento/Bundle/Model/Option/SaveAction.php b/app/code/Magento/Bundle/Model/Option/SaveAction.php index 176484d8ccbcf..42349f2f2cc2e 100644 --- a/app/code/Magento/Bundle/Model/Option/SaveAction.php +++ b/app/code/Magento/Bundle/Model/Option/SaveAction.php @@ -44,11 +44,6 @@ class SaveAction */ private $linkManagement; - /** - * @var StoreManagerInterface - */ - private $storeManager; - /** * @param Option $optionResource * @param MetadataPool $metadataPool @@ -67,8 +62,6 @@ public function __construct( $this->metadataPool = $metadataPool; $this->type = $type; $this->linkManagement = $linkManagement; - $this->storeManager = $storeManager - ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); } /** From 88ea96371386e36c7ca14eea5d7a3c6db0e07207 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <engcom-vendorworker-foxtrot@adobe.com> Date: Thu, 14 Jan 2021 17:26:58 +0200 Subject: [PATCH 14/16] magento/magento2#12584 Bundle Item price cannot differ per website - integration tests fix. --- .../DynamicBundlePriceCalculatorTest.php | 30 +++++++++++++++++++ ...BundlePriceCalculatorWithDimensionTest.php | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php index 1775f09eb58c7..4d7a1a64cd455 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php @@ -163,6 +163,8 @@ private function getBundleConfiguration1() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], ] ], @@ -192,14 +194,20 @@ private function getBundleConfiguration2() [ 'sku' => 'simple1', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 2, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple3', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], ] ] @@ -229,14 +237,20 @@ private function getBundleConfiguration3() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple3', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ] ] ] @@ -265,10 +279,14 @@ private function getBundleConfiguration4() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ], @@ -280,10 +298,14 @@ private function getBundleConfiguration4() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ] @@ -312,10 +334,14 @@ private function getBundleConfiguration5() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ], @@ -327,10 +353,14 @@ private function getBundleConfiguration5() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ] diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorWithDimensionTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorWithDimensionTest.php index b008fe4003c39..ba451c0fd4620 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorWithDimensionTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorWithDimensionTest.php @@ -163,6 +163,8 @@ private function getBundleConfiguration1() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], ] ], @@ -192,14 +194,20 @@ private function getBundleConfiguration2() [ 'sku' => 'simple1', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 2, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple3', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], ] ] @@ -229,14 +237,20 @@ private function getBundleConfiguration3() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple3', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ] ] ] @@ -265,10 +279,14 @@ private function getBundleConfiguration4() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ], @@ -280,10 +298,14 @@ private function getBundleConfiguration4() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ] @@ -312,10 +334,14 @@ private function getBundleConfiguration5() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ], @@ -327,10 +353,14 @@ private function getBundleConfiguration5() [ 'sku' => 'simple1', 'qty' => 1, + 'price' => 100, + 'price_type' => 0, ], [ 'sku' => 'simple2', 'qty' => 3, + 'price' => 100, + 'price_type' => 0, ], ] ] From c57d4d00eed8b06eb4889f5614399bde28f15ef0 Mon Sep 17 00:00:00 2001 From: Gabriel Galvao da Gama <galvaoda@adobe.com> Date: Wed, 27 Jan 2021 13:50:36 +0000 Subject: [PATCH 15/16] Removed unnecessary parameter --- app/code/Magento/Bundle/Model/LinkManagement.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Bundle/Model/LinkManagement.php b/app/code/Magento/Bundle/Model/LinkManagement.php index ca34c0e5423fb..b9c939d8d4899 100644 --- a/app/code/Magento/Bundle/Model/LinkManagement.php +++ b/app/code/Magento/Bundle/Model/LinkManagement.php @@ -173,13 +173,11 @@ public function saveChild( ) ); } - $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $selectionModel = $this->mapProductLinkToBundleSelectionModel( $selectionModel, $linkedProduct, $product, - (int)$linkProductModel->getId(), - $linkField + (int)$linkProductModel->getId() ); try { @@ -256,9 +254,9 @@ private function mapProductLinkToBundleSelectionModel( Selection $selectionModel, LinkInterface $productLink, ProductInterface $parentProduct, - int $linkedProductId, - string $linkField + int $linkedProductId ): Selection { + $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $selectionModel->setProductId($linkedProductId); $selectionModel->setParentProductId($parentProduct->getData($linkField)); if ($productLink->getSelectionId() !== null) { @@ -357,8 +355,7 @@ public function addChild( $selectionModel, $linkedProduct, $product, - (int)$linkProductModel->getEntityId(), - $linkField + (int)$linkProductModel->getEntityId() ); $selectionModel->setOptionId($optionId); From 27627ca83f71734f7cf290af5ac8ac9c374a4c63 Mon Sep 17 00:00:00 2001 From: Gabriel Galvao da Gama <galvaoda@adobe.com> Date: Thu, 28 Jan 2021 14:02:46 +0000 Subject: [PATCH 16/16] Fixed unit tests --- .../Magento/Bundle/Test/Unit/Model/LinkManagementTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index 5ced384a66a88..091dec8e1dc82 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -549,7 +549,7 @@ public function testAddChildCouldNotSave() $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); - $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); + $this->metadataMock->expects($this->exactly(2))->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); $productMock->expects($this->once()) ->method('getTypeId') @@ -626,7 +626,7 @@ public function testAddChild() $productLink->method('getOptionId')->willReturn(1); $productLink->method('getSelectionId')->willReturn(1); - $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); + $this->metadataMock->expects($this->exactly(2))->method('getLinkField')->willReturn($this->linkField); $productMock = $this->createMock(Product::class); $productMock->expects($this->once())->method('getTypeId')->willReturn(Type::TYPE_BUNDLE); $productMock