From 90b6803aab559cd0c345ab42d19bb712e4df8011 Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Fri, 22 Jun 2018 17:48:44 +0300 Subject: [PATCH 01/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Use configurable product`s children for shopping cart rules validation for cases when attribute exists for children only (E.g. special_price) --- .../Model/Rule/Condition/Product.php | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index 499e35db9dfd6..35ace4b6b089e 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -5,10 +5,14 @@ */ namespace Magento\SalesRule\Model\Rule\Condition; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable; + /** * Product rule condition data model * * @author Magento Core Team + * + * @method string getAttribute() */ class Product extends \Magento\Rule\Model\Condition\Product\AbstractProduct { @@ -26,20 +30,47 @@ protected function _addSpecialAttributes(array &$attributes) $attributes['quote_item_row_total'] = __('Row total in cart'); } + /** + * @param \Magento\Framework\Model\AbstractModel $model + * + * @return \Magento\Catalog\Api\Data\ProductInterface|\Magento\Catalog\Model\Product + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + protected function getProductToValidate(\Magento\Framework\Model\AbstractModel $model) + { + /** @var \Magento\Catalog\Model\Product $product */ + $product = $model->getProduct(); + if (!$product instanceof \Magento\Catalog\Model\Product) { + $product = $this->productRepository->getById($model->getProductId()); + } + + $attrCode = $this->getAttribute(); + + /* Check for attributes which are not available for configurable products */ + if ($product->getTypeId() == Configurable::TYPE_CODE && !$product->hasData($attrCode)) { + /** @var \Magento\Catalog\Api\Data\ProductInterface $childProduct */ + $childProduct = current($model->getChildren())->getProduct(); + if ($childProduct->hasData($attrCode)) { + $product = $childProduct; + } + } + + return $product; + } + /** * Validate Product Rule Condition * * @param \Magento\Framework\Model\AbstractModel $model + * * @return bool + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function validate(\Magento\Framework\Model\AbstractModel $model) { //@todo reimplement this method when is fixed MAGETWO-5713 /** @var \Magento\Catalog\Model\Product $product */ - $product = $model->getProduct(); - if (!$product instanceof \Magento\Catalog\Model\Product) { - $product = $this->productRepository->getById($model->getProductId()); - } + $product = $this->getProductToValidate($model); $product->setQuoteItemQty( $model->getQty() @@ -49,9 +80,8 @@ public function validate(\Magento\Framework\Model\AbstractModel $model) $model->getBaseRowTotal() ); - $attrCode = $this->getAttribute(); - if ('category_ids' == $attrCode) { + if ('category_ids' == $this->getAttribute()) { return $this->validateAttribute($this->_getAvailableInCategories($product->getId())); } From 2717cb1729b6f1b61040f3eb1582eb1d60622893 Mon Sep 17 00:00:00 2001 From: Riccardo Tempesta Date: Mon, 25 Jun 2018 22:19:16 +0200 Subject: [PATCH 02/14] Removed empty line due to failing static test --- app/code/Magento/SalesRule/Model/Rule/Condition/Product.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index 35ace4b6b089e..8a9e6f7f2b66c 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -80,7 +80,6 @@ public function validate(\Magento\Framework\Model\AbstractModel $model) $model->getBaseRowTotal() ); - if ('category_ids' == $this->getAttribute()) { return $this->validateAttribute($this->_getAvailableInCategories($product->getId())); } From d2a0de83c0f73dd850925b4a70ab2e5cf233d74b Mon Sep 17 00:00:00 2001 From: Riccardo Tempesta Date: Tue, 26 Jun 2018 16:25:41 +0200 Subject: [PATCH 03/14] Removed dependency to configurable product --- app/code/Magento/SalesRule/Model/Rule/Condition/Product.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index 8a9e6f7f2b66c..e17cc9b16535e 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -5,8 +5,6 @@ */ namespace Magento\SalesRule\Model\Rule\Condition; -use Magento\ConfigurableProduct\Model\Product\Type\Configurable; - /** * Product rule condition data model * @@ -47,7 +45,7 @@ protected function getProductToValidate(\Magento\Framework\Model\AbstractModel $ $attrCode = $this->getAttribute(); /* Check for attributes which are not available for configurable products */ - if ($product->getTypeId() == Configurable::TYPE_CODE && !$product->hasData($attrCode)) { + if ($product->isComposite() && !$product->hasData($attrCode)) { /** @var \Magento\Catalog\Api\Data\ProductInterface $childProduct */ $childProduct = current($model->getChildren())->getProduct(); if ($childProduct->hasData($attrCode)) { From fae98c01e29ea9ca47eca00cf2081ede1f729ccb Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Wed, 4 Jul 2018 22:55:35 +0300 Subject: [PATCH 04/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Revert "Removed dependency to configurable product" This reverts commit d2a0de83c0f73dd850925b4a70ab2e5cf233d74b. --- app/code/Magento/SalesRule/Model/Rule/Condition/Product.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index e17cc9b16535e..8a9e6f7f2b66c 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -5,6 +5,8 @@ */ namespace Magento\SalesRule\Model\Rule\Condition; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable; + /** * Product rule condition data model * @@ -45,7 +47,7 @@ protected function getProductToValidate(\Magento\Framework\Model\AbstractModel $ $attrCode = $this->getAttribute(); /* Check for attributes which are not available for configurable products */ - if ($product->isComposite() && !$product->hasData($attrCode)) { + if ($product->getTypeId() == Configurable::TYPE_CODE && !$product->hasData($attrCode)) { /** @var \Magento\Catalog\Api\Data\ProductInterface $childProduct */ $childProduct = current($model->getChildren())->getProduct(); if ($childProduct->hasData($attrCode)) { From 9a35b459f1b31b2b8d40c6597bd90ac9c5c865fe Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Wed, 4 Jul 2018 22:57:37 +0300 Subject: [PATCH 05/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Made getProductToValidate method private according to Technical Guideline (2.7) --- app/code/Magento/SalesRule/Model/Rule/Condition/Product.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index 8a9e6f7f2b66c..07a2ea1a87b6e 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -36,7 +36,7 @@ protected function _addSpecialAttributes(array &$attributes) * @return \Magento\Catalog\Api\Data\ProductInterface|\Magento\Catalog\Model\Product * @throws \Magento\Framework\Exception\NoSuchEntityException */ - protected function getProductToValidate(\Magento\Framework\Model\AbstractModel $model) + private function getProductToValidate(\Magento\Framework\Model\AbstractModel $model) { /** @var \Magento\Catalog\Model\Product $product */ $product = $model->getProduct(); From 887ee4aa918340a5933c9923c334cef6b97d44eb Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Sat, 7 Jul 2018 22:10:05 +0300 Subject: [PATCH 06/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Added configurable product to dependencies --- app/code/Magento/SalesRule/composer.json | 3 ++- app/code/Magento/SalesRule/etc/module.xml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index f030482bcf240..e282e035ad23f 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -19,7 +19,8 @@ "magento/module-widget": "101.0.*", "magento/module-quote": "101.0.*", "magento/module-ui": "101.0.*", - "magento/framework": "101.0.*" + "magento/framework": "101.0.*", + "magento/module-configurable-product": "100.*" }, "suggest": { "magento/module-sales-rule-sample-data": "Sample Data version:100.2.*" diff --git a/app/code/Magento/SalesRule/etc/module.xml b/app/code/Magento/SalesRule/etc/module.xml index f3f160eb7d40b..1df09b97b9353 100644 --- a/app/code/Magento/SalesRule/etc/module.xml +++ b/app/code/Magento/SalesRule/etc/module.xml @@ -12,6 +12,7 @@ + From 0c9aa81d514717a4761c716260130e87fb08980e Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Sun, 22 Jul 2018 12:30:36 +0300 Subject: [PATCH 07/14] Revert "#14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Added configurable product to dependencies" This reverts commit 887ee4a --- app/code/Magento/SalesRule/composer.json | 3 +-- app/code/Magento/SalesRule/etc/module.xml | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index e282e035ad23f..f030482bcf240 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -19,8 +19,7 @@ "magento/module-widget": "101.0.*", "magento/module-quote": "101.0.*", "magento/module-ui": "101.0.*", - "magento/framework": "101.0.*", - "magento/module-configurable-product": "100.*" + "magento/framework": "101.0.*" }, "suggest": { "magento/module-sales-rule-sample-data": "Sample Data version:100.2.*" diff --git a/app/code/Magento/SalesRule/etc/module.xml b/app/code/Magento/SalesRule/etc/module.xml index 1df09b97b9353..f3f160eb7d40b 100644 --- a/app/code/Magento/SalesRule/etc/module.xml +++ b/app/code/Magento/SalesRule/etc/module.xml @@ -12,7 +12,6 @@ - From 5b95b223b6bb3aa6ee292364486837a51e74ce31 Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Sun, 22 Jul 2018 12:47:17 +0300 Subject: [PATCH 08/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Restored \Magento\SalesRule\Model\Rule\Condition\Product to its previous state except PHPDocs. --- .../Model/Rule/Condition/Product.php | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index 18baa786c942b..0b8b7fc046a24 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -6,8 +6,6 @@ namespace Magento\SalesRule\Model\Rule\Condition; -use Magento\ConfigurableProduct\Model\Product\Type\Configurable; - /** * Product rule condition data model * @@ -31,34 +29,6 @@ protected function _addSpecialAttributes(array &$attributes) $attributes['quote_item_row_total'] = __('Row total in cart'); } - /** - * @param \Magento\Framework\Model\AbstractModel $model - * - * @return \Magento\Catalog\Api\Data\ProductInterface|\Magento\Catalog\Model\Product - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ - private function getProductToValidate(\Magento\Framework\Model\AbstractModel $model) - { - /** @var \Magento\Catalog\Model\Product $product */ - $product = $model->getProduct(); - if (!$product instanceof \Magento\Catalog\Model\Product) { - $product = $this->productRepository->getById($model->getProductId()); - } - - $attrCode = $this->getAttribute(); - - /* Check for attributes which are not available for configurable products */ - if ($product->getTypeId() == Configurable::TYPE_CODE && !$product->hasData($attrCode)) { - /** @var \Magento\Catalog\Api\Data\ProductInterface $childProduct */ - $childProduct = current($model->getChildren())->getProduct(); - if ($childProduct->hasData($attrCode)) { - $product = $childProduct; - } - } - - return $product; - } - /** * Validate Product Rule Condition * @@ -71,7 +41,10 @@ public function validate(\Magento\Framework\Model\AbstractModel $model) { //@todo reimplement this method when is fixed MAGETWO-5713 /** @var \Magento\Catalog\Model\Product $product */ - $product = $this->getProductToValidate($model); + $product = $model->getProduct(); + if (!$product instanceof \Magento\Catalog\Model\Product) { + $product = $this->productRepository->getById($model->getProductId()); + } $product->setQuoteItemQty( $model->getQty() From 618f408b2af3ff6c541cdc90d110de0a5827a66a Mon Sep 17 00:00:00 2001 From: MaxNovik Date: Sun, 22 Jul 2018 13:35:11 +0300 Subject: [PATCH 09/14] Moved adjustments to plugin. --- .../Model/Rule/Condition/Product.php | 54 +++++++++++++++++++ .../Magento/ConfigurableProduct/composer.json | 1 + .../Magento/ConfigurableProduct/etc/di.xml | 3 ++ 3 files changed, 58 insertions(+) create mode 100644 app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php diff --git a/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php new file mode 100644 index 0000000000000..a2fe0be4a7523 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php @@ -0,0 +1,54 @@ +setProduct( + $this->getProductToValidate($subject, $model) + ); + } + + + /** + * @param \Magento\SalesRule\Model\Rule\Condition\Product $subject + * @param \Magento\Framework\Model\AbstractModel $model + * + * @return \Magento\Catalog\Api\Data\ProductInterface|\Magento\Catalog\Model\Product + */ + private function getProductToValidate( + \Magento\SalesRule\Model\Rule\Condition\Product $subject, + \Magento\Framework\Model\AbstractModel $model + ) { + /** @var \Magento\Catalog\Model\Product $product */ + $product = $model->getProduct(); + + $attrCode = $subject->getAttribute(); + + /* Check for attributes which are not available for configurable products */ + if ($product->getTypeId() == Configurable::TYPE_CODE && !$product->hasData($attrCode)) { + /** @var \Magento\Catalog\Model\AbstractModel $childProduct */ + $childProduct = current($model->getChildren())->getProduct(); + if ($childProduct->hasData($attrCode)) { + $product = $childProduct; + } + } + + return $product; + } +} diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json index 4c583d79ce418..f2818883a131b 100644 --- a/app/code/Magento/ConfigurableProduct/composer.json +++ b/app/code/Magento/ConfigurableProduct/composer.json @@ -19,6 +19,7 @@ "suggest": { "magento/module-webapi": "100.2.*", "magento/module-sales": "101.0.*", + "magento/module-sales-rule": "101.0.*", "magento/module-product-video": "100.2.*", "magento/module-configurable-sample-data": "Sample Data version:100.2.*", "magento/module-product-links-sample-data": "Sample Data version:100.2.*" diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 43e70f3766dca..d19fa7dcb29fe 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -221,4 +221,7 @@ + + + From 7c8482bccf6d6d55d89b743dc74f00278c9b8f95 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Mon, 23 Jul 2018 10:32:40 +0300 Subject: [PATCH 10/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products Removed an empty line. --- .../Plugin/SalesRule/Model/Rule/Condition/Product.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php index a2fe0be4a7523..183d21b0bddcb 100644 --- a/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/ConfigurableProduct/Plugin/SalesRule/Model/Rule/Condition/Product.php @@ -24,7 +24,6 @@ public function beforeValidate( ); } - /** * @param \Magento\SalesRule\Model\Rule\Condition\Product $subject * @param \Magento\Framework\Model\AbstractModel $model From 8d417ac4192cdddb191686c5de8b18e5cda99032 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Thu, 9 Aug 2018 16:06:07 +0300 Subject: [PATCH 11/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Unit tests coverage: case when child should be used --- .../Model/Rule/Condition/ProductTest.php | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php new file mode 100644 index 0000000000000..4478c225dedfa --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php @@ -0,0 +1,198 @@ +objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->validator = $this->createValidator(); + $this->validatorPlugin = $this->objectManager->getObject(ValidatorPlugin::class); + } + + /** + * @return \Magento\SalesRule\Model\Rule\Condition\Product + */ + private function createValidator(): SalesRuleProduct + { + /** @var Context|\PHPUnit_Framework_MockObject_MockObject $contextMock */ + $contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var Data|\PHPUnit_Framework_MockObject_MockObject $backendHelperMock */ + $backendHelperMock = $this->getMockBuilder(Data::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var Config|\PHPUnit_Framework_MockObject_MockObject $configMock */ + $configMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var ProductFactory|\PHPUnit_Framework_MockObject_MockObject $productFactoryMock */ + $productFactoryMock = $this->getMockBuilder(ProductFactory::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var ProductRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $productRepositoryMock */ + $productRepositoryMock = $this->getMockBuilder(ProductRepositoryInterface::class) + ->getMockForAbstractClass(); + $attributeLoaderInterfaceMock = $this->getMockBuilder(AbstractEntity::class) + ->disableOriginalConstructor() + ->setMethods(['getAttributesByCode']) + ->getMock(); + $attributeLoaderInterfaceMock + ->expects($this->any()) + ->method('getAttributesByCode') + ->willReturn([]); + /** @var Product|\PHPUnit_Framework_MockObject_MockObject $productMock */ + $productMock = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->setMethods(['loadAllAttributes', 'getConnection', 'getTable']) + ->getMock(); + $productMock->expects($this->any()) + ->method('loadAllAttributes') + ->willReturn($attributeLoaderInterfaceMock); + /** @var Collection|\PHPUnit_Framework_MockObject_MockObject $collectionMock */ + $collectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var FormatInterface|\PHPUnit_Framework_MockObject_MockObject $formatMock */ + $formatMock = new Format( + $this->getMockBuilder(ScopeResolverInterface::class)->disableOriginalConstructor()->getMock(), + $this->getMockBuilder(ResolverInterface::class)->disableOriginalConstructor()->getMock(), + $this->getMockBuilder(CurrencyFactory::class)->disableOriginalConstructor()->getMock() + ); + + return new SalesRuleProduct( + $contextMock, + $backendHelperMock, + $configMock, + $productFactoryMock, + $productRepositoryMock, + $productMock, + $collectionMock, + $formatMock + ); + } + + public function testChildIsUsedForValidation() + { + $configurableProductMock = $this->createProductMock(); + $configurableProductMock + ->expects($this->any()) + ->method('getTypeId') + ->willReturn(Configurable::TYPE_CODE); + $configurableProductMock + ->expects($this->any()) + ->method('hasData') + ->with($this->equalTo('special_price')) + ->willReturn(false); + + /* @var AbstractItem|\PHPUnit_Framework_MockObject_MockObject $item */ + $item = $this->getMockBuilder(AbstractItem::class) + ->disableOriginalConstructor() + ->setMethods(['setProduct', 'getProduct', 'getChildren']) + ->getMockForAbstractClass(); + $item->expects($this->any()) + ->method('getProduct') + ->willReturn($configurableProductMock); + + $simpleProductMock = $this->createProductMock(); + $simpleProductMock + ->expects($this->any()) + ->method('getTypeId') + ->willReturn(Type::TYPE_SIMPLE); + $simpleProductMock + ->expects($this->any()) + ->method('hasData') + ->with($this->equalTo('special_price')) + ->willReturn(true); + + $childItem = $this->getMockBuilder(AbstractItem::class) + ->disableOriginalConstructor() + ->setMethods(['getProduct']) + ->getMockForAbstractClass(); + $childItem->expects($this->any()) + ->method('getProduct') + ->willReturn($simpleProductMock); + + $item->expects($this->any()) + ->method('getChildren') + ->willReturn([$childItem]); + $item->expects($this->once()) + ->method('setProduct') + ->with($simpleProductMock); + + $this->validator->setAttribute('special_price'); + + $this->validatorPlugin->beforeValidate($this->validator, $item); + } + + /** + * @return Product|\PHPUnit_Framework_MockObject_MockObject + */ + private function createProductMock(): \PHPUnit_Framework_MockObject_MockObject + { + $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getAttribute', + 'getId', + 'setQuoteItemQty', + 'setQuoteItemPrice', + 'getTypeId', + 'hasData', + ]) + ->getMock(); + $productMock + ->expects($this->any()) + ->method('setQuoteItemQty') + ->willReturnSelf(); + $productMock + ->expects($this->any()) + ->method('setQuoteItemPrice') + ->willReturnSelf(); + + return $productMock; + } +} From 90ff989212c73ee31b75c06d1f9c14efae4715aa Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Thu, 9 Aug 2018 16:49:51 +0300 Subject: [PATCH 12/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Fixed mock objects comparison --- .../Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php index 4478c225dedfa..f7efb97a1d75a 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php @@ -161,7 +161,7 @@ public function testChildIsUsedForValidation() ->willReturn([$childItem]); $item->expects($this->once()) ->method('setProduct') - ->with($simpleProductMock); + ->with($this->identicalTo($simpleProductMock)); $this->validator->setAttribute('special_price'); From c52e0e856f5edb657867d65fcf88702eef00ca37 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Thu, 9 Aug 2018 17:00:27 +0300 Subject: [PATCH 13/14] Covered case when simple product is being validated --- .../Model/Rule/Condition/ProductTest.php | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php index f7efb97a1d75a..50200a6707d96 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php @@ -90,8 +90,8 @@ private function createValidator(): SalesRuleProduct ->setMethods(['loadAllAttributes', 'getConnection', 'getTable']) ->getMock(); $productMock->expects($this->any()) - ->method('loadAllAttributes') - ->willReturn($attributeLoaderInterfaceMock); + ->method('loadAllAttributes') + ->willReturn($attributeLoaderInterfaceMock); /** @var Collection|\PHPUnit_Framework_MockObject_MockObject $collectionMock */ $collectionMock = $this->getMockBuilder(Collection::class) ->disableOriginalConstructor() @@ -195,4 +195,35 @@ private function createProductMock(): \PHPUnit_Framework_MockObject_MockObject return $productMock; } + + public function testChildIsNotUsedForValidation() + { + $simpleProductMock = $this->createProductMock(); + $simpleProductMock + ->expects($this->any()) + ->method('getTypeId') + ->willReturn(Type::TYPE_SIMPLE); + $simpleProductMock + ->expects($this->any()) + ->method('hasData') + ->with($this->equalTo('special_price')) + ->willReturn(true); + + /* @var AbstractItem|\PHPUnit_Framework_MockObject_MockObject $item */ + $item = $this->getMockBuilder(AbstractItem::class) + ->disableOriginalConstructor() + ->setMethods(['setProduct', 'getProduct']) + ->getMockForAbstractClass(); + $item->expects($this->any()) + ->method('getProduct') + ->willReturn($simpleProductMock); + + $item->expects($this->once()) + ->method('setProduct') + ->with($this->identicalTo($simpleProductMock)); + + $this->validator->setAttribute('special_price'); + + $this->validatorPlugin->beforeValidate($this->validator, $item); + } } From 5c3154b665f1843ab8de50396a9fe739b021cea6 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Thu, 9 Aug 2018 23:18:36 +0300 Subject: [PATCH 14/14] #14020-Cart-Sales-Rule-with-negated-condition-over-special-price-does-not-work-for-configurable-products. Fixed static tests. --- .../Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php index 50200a6707d96..b1fc09e9676a2 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/SalesRule/Model/Rule/Condition/ProductTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\ConfigurableProduct\Plugin\SalesRule\Model\Rule\Condition; +namespace Magento\ConfigurableProduct\Test\Unit\Plugin\SalesRule\Model\Rule\Condition; use Magento\Backend\Helper\Data; use Magento\Catalog\Api\ProductRepositoryInterface; @@ -27,6 +27,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.LongVariable) */ class ProductTest extends \PHPUnit\Framework\TestCase {