Skip to content

Commit 0f8e716

Browse files
committed
MAGETWO-85781: Configurable product Final Price ignores Catalog Rule
1 parent 29e8cab commit 0f8e716

File tree

7 files changed

+271
-27
lines changed

7 files changed

+271
-27
lines changed

app/code/Magento/CatalogRule/Model/Rule/Condition/Product.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function validate(\Magento\Framework\Model\AbstractModel $model)
2424
{
2525
$attrCode = $this->getAttribute();
2626
if ('category_ids' == $attrCode) {
27-
return $this->validateAttribute($model->getAvailableInCategories());
27+
return parent::validate($model);
2828
}
2929

3030
$oldAttrValue = $model->getData($attrCode);

app/code/Magento/CatalogRule/Test/Unit/Model/Rule/Condition/ProductTest.php

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,22 @@ class ProductTest extends \PHPUnit_Framework_TestCase
2828
/** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute|\PHPUnit_Framework_MockObject_MockObject */
2929
protected $eavAttributeResource;
3030

31+
/** @var \Magento\Catalog\Model\ResourceModel\Category|\PHPUnit_Framework_MockObject_MockObject */
32+
private $category;
33+
34+
/** @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject */
35+
private $connection;
36+
37+
/** @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject */
38+
private $dbSelect;
39+
3140
protected function setUp()
3241
{
3342
$this->config = $this->getMock('Magento\Eav\Model\Config', ['getAttribute'], [], '', false);
3443
$this->productModel = $this->getMock(
3544
'Magento\Catalog\Model\Product',
3645
[
3746
'__wakeup',
38-
'getAvailableInCategories',
3947
'hasData',
4048
'getData',
4149
'getId',
@@ -47,16 +55,21 @@ protected function setUp()
4755
'',
4856
false
4957
);
50-
$this->productResource = $this->getMock(
51-
'Magento\Catalog\Model\ResourceModel\Product',
52-
['loadAllAttributes',
53-
'getAttributesByCode',
54-
'getAttribute'
55-
],
56-
[],
57-
'',
58-
false
59-
);
58+
$this->category = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Category::class)
59+
->disableOriginalConstructor()
60+
->getMock();
61+
$this->productResource = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class)
62+
->setMethods(['loadAllAttributes', 'getAttributesByCode', 'getAttribute', 'getConnection', 'getTable'])
63+
->disableOriginalConstructor()
64+
->getMock();
65+
$this->connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
66+
->disableOriginalConstructor()
67+
->getMockForAbstractClass();
68+
$this->dbSelect = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
69+
->disableOriginalConstructor()
70+
->setMethods(['from', 'where'])
71+
->getMock();
72+
6073
$this->eavAttributeResource = $this->getMock(
6174
'\Magento\Catalog\Model\ResourceModel\Eav\Attribute',
6275
[
@@ -93,7 +106,8 @@ protected function setUp()
93106
[
94107
'config' => $this->config,
95108
'product' => $this->productModel,
96-
'productResource' => $this->productResource
109+
'productResource' => $this->productResource,
110+
'category' => $this->category
97111
]
98112
);
99113
}
@@ -103,12 +117,27 @@ protected function setUp()
103117
*/
104118
public function testValidateMeetsCategory()
105119
{
120+
$categoryIdList = [1, 2, 3];
121+
122+
$this->productResource->expects($this->atLeastOnce())
123+
->method('getConnection')
124+
->willReturn($this->connection);
125+
$this->connection->expects($this->atLeastOnce())
126+
->method('select')
127+
->willReturn($this->dbSelect);
128+
$this->dbSelect->expects($this->atLeastOnce())
129+
->method('from')
130+
->willReturnSelf();
131+
$this->dbSelect->expects($this->atLeastOnce())
132+
->method('where')
133+
->willReturnSelf();
134+
$this->connection->expects($this->once())
135+
->method('fetchCol')
136+
->willReturn($categoryIdList);
106137
$this->product->setData('attribute', 'category_ids');
107138
$this->product->setData('value_parsed', '1');
108-
$this->product->setData('operator', '>=');
139+
$this->product->setData('operator', '{}');
109140

110-
$this->productModel->expects($this->once())->method('getAvailableInCategories')
111-
->will($this->returnValue('2'));
112141
$this->assertTrue($this->product->validate($this->productModel));
113142
}
114143

app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
/**
1414
* Class Product
15+
*
16+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1517
*/
1618
class Product extends \Magento\Rule\Model\Condition\Product\AbstractProduct
1719
{
@@ -43,6 +45,7 @@ class Product extends \Magento\Rule\Model\Condition\Product\AbstractProduct
4345
* @param \Magento\Framework\Locale\FormatInterface $localeFormat
4446
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
4547
* @param array $data
48+
* @param \Magento\Catalog\Model\ResourceModel\Category $category
4649
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
4750
*/
4851
public function __construct(
@@ -55,7 +58,8 @@ public function __construct(
5558
\Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection $attrSetCollection,
5659
\Magento\Framework\Locale\FormatInterface $localeFormat,
5760
\Magento\Store\Model\StoreManagerInterface $storeManager,
58-
array $data = []
61+
array $data = [],
62+
\Magento\Catalog\Model\ResourceModel\Category $category = null
5963
) {
6064
$this->storeManager = $storeManager;
6165
parent::__construct(
@@ -67,7 +71,8 @@ public function __construct(
6771
$productResource,
6872
$attrSetCollection,
6973
$localeFormat,
70-
$data
74+
$data,
75+
$category
7176
);
7277
}
7378

app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
*/
1212
namespace Magento\Rule\Model\Condition\Product;
1313

14+
use Magento\Catalog\Model\Indexer\Category\Product\AbstractAction;
15+
use Magento\Framework\DB\Select;
16+
use Magento\Framework\DB\Sql\UnionExpression;
17+
1418
/**
1519
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
1620
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -79,6 +83,16 @@ abstract class AbstractProduct extends \Magento\Rule\Model\Condition\AbstractCon
7983
*/
8084
protected $_localeFormat;
8185

86+
/**
87+
* @var \Magento\Catalog\Model\ResourceModel\Category
88+
*/
89+
private $category;
90+
91+
/**
92+
* @var array
93+
*/
94+
private $categoryIdList = [];
95+
8296
/**
8397
* @param \Magento\Rule\Model\Condition\Context $context
8498
* @param \Magento\Backend\Helper\Data $backendData
@@ -88,7 +102,10 @@ abstract class AbstractProduct extends \Magento\Rule\Model\Condition\AbstractCon
88102
* @param \Magento\Catalog\Model\ResourceModel\Product $productResource
89103
* @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection $attrSetCollection
90104
* @param \Magento\Framework\Locale\FormatInterface $localeFormat
105+
* @param \Magento\Catalog\Model\ResourceModel\Category|null $category
91106
* @param array $data
107+
*
108+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
92109
*/
93110
public function __construct(
94111
\Magento\Rule\Model\Condition\Context $context,
@@ -99,7 +116,8 @@ public function __construct(
99116
\Magento\Catalog\Model\ResourceModel\Product $productResource,
100117
\Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection $attrSetCollection,
101118
\Magento\Framework\Locale\FormatInterface $localeFormat,
102-
array $data = []
119+
array $data = [],
120+
\Magento\Catalog\Model\ResourceModel\Category $category = null
103121
) {
104122
$this->_backendData = $backendData;
105123
$this->_config = $config;
@@ -108,6 +126,8 @@ public function __construct(
108126
$this->_productResource = $productResource;
109127
$this->_attrSetCollection = $attrSetCollection;
110128
$this->_localeFormat = $localeFormat;
129+
$this->category = $category ?: \Magento\Framework\App\ObjectManager::getInstance()
130+
->get(\Magento\Catalog\Model\ResourceModel\Category::class);
111131
parent::__construct($context, $data);
112132
}
113133

@@ -520,7 +540,8 @@ public function validate(\Magento\Framework\Model\AbstractModel $model)
520540
$attrCode = $this->getAttribute();
521541

522542
if ('category_ids' == $attrCode) {
523-
return $this->validateAttribute($model->getAvailableInCategories());
543+
$productId = (int)$model->getEntityId();
544+
return $this->validateAttribute($this->getCategoryIds($productId));
524545
} elseif (!isset($this->_entityAttributeValues[$model->getId()])) {
525546
if (!$model->getResource()) {
526547
return false;
@@ -721,4 +742,48 @@ protected function getEavAttributeTableAlias()
721742

722743
return 'at_' . $attribute->getAttributeCode();
723744
}
745+
746+
/**
747+
* Retrieve category id list where product is present.
748+
*
749+
* @param int $productId
750+
* @return array
751+
*/
752+
private function getCategoryIds($productId)
753+
{
754+
if (!isset($this->categoryIdList[$productId])) {
755+
$unionSelect = new UnionExpression(
756+
[
757+
$this->getCategorySelect($productId, $this->category->getCategoryProductTable()),
758+
$this->getCategorySelect(
759+
$productId,
760+
$this->_productResource->getTable(AbstractAction::MAIN_INDEX_TABLE)
761+
)
762+
],
763+
Select::SQL_UNION_ALL
764+
);
765+
766+
$this->categoryIdList[$productId] = $this->_productResource->getConnection()->fetchCol($unionSelect);
767+
}
768+
769+
return $this->categoryIdList[$productId];
770+
}
771+
772+
/**
773+
* Returns DB select.
774+
*
775+
* @param int $productId
776+
* @param string $tableName
777+
* @return Select
778+
*/
779+
private function getCategorySelect($productId, $tableName)
780+
{
781+
return $this->_productResource->getConnection()->select()->from(
782+
$tableName,
783+
['category_id']
784+
)->where(
785+
'product_id = ?',
786+
$productId
787+
);
788+
}
724789
}

app/code/Magento/Rule/Test/Unit/Model/Condition/Product/AbstractProductTest.php

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class AbstractProductTest extends \PHPUnit_Framework_TestCase
3939
*/
4040
protected $_configProperty;
4141

42+
/** @var \ReflectionProperty */
43+
private $categoryProperty;
44+
45+
/** @var \ReflectionProperty */
46+
private $productResourceProperty;
47+
4248
protected function setUp()
4349
{
4450
$this->_condition = $this->getMockForAbstractClass(
@@ -58,14 +64,82 @@ protected function setUp()
5864
'_config'
5965
);
6066
$this->_configProperty->setAccessible(true);
67+
68+
$this->categoryProperty = new \ReflectionProperty(
69+
\Magento\Rule\Model\Condition\Product\AbstractProduct::class,
70+
'category'
71+
);
72+
$this->categoryProperty->setAccessible(true);
73+
74+
$this->productResourceProperty = new \ReflectionProperty(
75+
\Magento\Rule\Model\Condition\Product\AbstractProduct::class,
76+
'_productResource'
77+
);
78+
$this->productResourceProperty->setAccessible(true);
6179
}
6280

6381
public function testValidateAttributeEqualCategoryId()
6482
{
65-
$product = $this->getMock('Magento\Framework\Model\AbstractModel', ["getAttribute"], [], '', false);
83+
$product = $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class)
84+
->disableOriginalConstructor()
85+
->setMethods(['getCategoryIds'])
86+
->getMock();
87+
6688
$this->_condition->setAttribute('category_ids');
67-
$product->setAvailableInCategories(new \Magento\Framework\DataObject());
68-
$this->assertFalse($this->_condition->validate($product));
89+
$this->_condition->setValueParsed('1');
90+
$this->_condition->setOperator('{}');
91+
92+
$this->_configProperty->setValue(
93+
$this->_condition,
94+
$this->getMockBuilder(\Magento\Eav\Model\Config::class)
95+
->disableOriginalConstructor()
96+
->getMock()
97+
);
98+
99+
$category = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Category::class)
100+
->disableOriginalConstructor()
101+
->getMock();
102+
$category->expects($this->once())
103+
->method('getCategoryProductTable')
104+
->willReturnSelf();
105+
$this->categoryProperty->setValue(
106+
$this->_condition,
107+
$category
108+
);
109+
110+
$dbSelect = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
111+
->disableOriginalConstructor()
112+
->setMethods(['from', 'where'])
113+
->getMock();
114+
$dbSelect->expects($this->atLeastOnce())
115+
->method('from')
116+
->willReturnSelf();
117+
$dbSelect->expects($this->atLeastOnce())
118+
->method('where')
119+
->willReturnSelf();
120+
121+
$connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
122+
->disableOriginalConstructor()
123+
->getMockForAbstractClass();
124+
$connection->expects($this->atLeastOnce())
125+
->method('select')
126+
->willReturn($dbSelect);
127+
$connection->expects($this->once())
128+
->method('fetchCol')
129+
->willReturn([1, 2]);
130+
131+
$resource = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class)
132+
->disableOriginalConstructor()
133+
->getMock();
134+
$resource->expects($this->atLeastOnce())
135+
->method('getConnection')
136+
->willReturn($connection);
137+
$this->productResourceProperty->setValue(
138+
$this->_condition,
139+
$resource
140+
);
141+
142+
$this->assertTrue($this->_condition->validate($product));
69143
}
70144

71145
public function testValidateEmptyEntityAttributeValues()

0 commit comments

Comments
 (0)