Skip to content

Commit 7d0efc5

Browse files
authored
Merge pull request #3835 from magento-tsg-csl3/2.3-develop-pr18
[TSG-CSL3] For 2.3 (pr18)
2 parents ef58edb + d9dfcca commit 7d0efc5

File tree

5 files changed

+332
-24
lines changed

5 files changed

+332
-24
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Test\Unit\Ui\Component;
9+
10+
use PHPUnit\Framework\TestCase;
11+
use Magento\Catalog\Ui\Component\ColumnFactory;
12+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
13+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
14+
use Magento\Framework\View\Element\UiComponent\ContextInterface;
15+
use Magento\Framework\View\Element\UiComponentFactory;
16+
use Magento\Ui\Component\Listing\Columns\ColumnInterface;
17+
use Magento\Ui\Component\Filters\FilterModifier;
18+
19+
/**
20+
* ColumnFactory test.
21+
*/
22+
class ColumnFactoryTest extends TestCase
23+
{
24+
/**
25+
* @var ColumnFactory
26+
*/
27+
private $columnFactory;
28+
29+
/**
30+
* @var ObjectManager
31+
*/
32+
private $objectManager;
33+
34+
/**
35+
* @var ProductAttributeInterface|\PHPUnit\Framework\MockObject\MockObject
36+
*/
37+
private $attribute;
38+
39+
/**
40+
* @var ContextInterface|\PHPUnit\Framework\MockObject\MockObject
41+
*/
42+
private $context;
43+
44+
/**
45+
* @var UiComponentFactory|\PHPUnit\Framework\MockObject\MockObject
46+
*/
47+
private $uiComponentFactory;
48+
49+
/**
50+
* @var ColumnInterface|\PHPUnit\Framework\MockObject\MockObject
51+
*/
52+
private $column;
53+
54+
/**
55+
* @inheritdoc
56+
*/
57+
protected function setUp(): void
58+
{
59+
$this->objectManager = new ObjectManager($this);
60+
61+
$this->attribute = $this->getMockBuilder(ProductAttributeInterface::class)
62+
->setMethods(['usesSource'])
63+
->getMockForAbstractClass();
64+
$this->context = $this->createMock(ContextInterface::class);
65+
$this->uiComponentFactory = $this->createMock(UiComponentFactory::class);
66+
$this->column = $this->getMockForAbstractClass(ColumnInterface::class);
67+
$this->uiComponentFactory->method('create')
68+
->willReturn($this->column);
69+
70+
$this->columnFactory = $this->objectManager->getObject(ColumnFactory::class, [
71+
'componentFactory' => $this->uiComponentFactory
72+
]);
73+
}
74+
75+
/**
76+
* Tests the create method will return correct object.
77+
*
78+
* @return void
79+
*/
80+
public function testCreatedObject(): void
81+
{
82+
$this->context->method('getRequestParam')
83+
->with(FilterModifier::FILTER_MODIFIER, [])
84+
->willReturn([]);
85+
86+
$object = $this->columnFactory->create($this->attribute, $this->context);
87+
$this->assertEquals(
88+
$this->column,
89+
$object,
90+
'Object must be the same which the ui component factory creates.'
91+
);
92+
}
93+
94+
/**
95+
* Tests create method with not filterable in grid attribute.
96+
*
97+
* @param array $filterModifiers
98+
* @param null|string $filter
99+
*
100+
* @return void
101+
* @dataProvider filterModifiersProvider
102+
*/
103+
public function testCreateWithNotFilterableInGridAttribute(array $filterModifiers, ?string $filter): void
104+
{
105+
$componentFactoryArgument = [
106+
'data' => [
107+
'config' => [
108+
'label' => __(null),
109+
'dataType' => 'text',
110+
'add_field' => true,
111+
'visible' => null,
112+
'filter' => $filter,
113+
'component' => 'Magento_Ui/js/grid/columns/column',
114+
],
115+
],
116+
'context' => $this->context,
117+
];
118+
119+
$this->context->method('getRequestParam')
120+
->with(FilterModifier::FILTER_MODIFIER, [])
121+
->willReturn($filterModifiers);
122+
$this->attribute->method('getIsFilterableInGrid')
123+
->willReturn(false);
124+
$this->attribute->method('getAttributeCode')
125+
->willReturn('color');
126+
127+
$this->uiComponentFactory->expects($this->once())
128+
->method('create')
129+
->with($this->anything(), $this->anything(), $componentFactoryArgument);
130+
131+
$this->columnFactory->create($this->attribute, $this->context);
132+
}
133+
134+
/**
135+
* Filter modifiers data provider.
136+
*
137+
* @return array
138+
*/
139+
public function filterModifiersProvider(): array
140+
{
141+
return [
142+
'without' => [
143+
'filter_modifiers' => [],
144+
'filter' => null,
145+
],
146+
'with' => [
147+
'filter_modifiers' => [
148+
'color' => [
149+
'condition_type' => 'notnull',
150+
],
151+
],
152+
'filter' => 'text',
153+
],
154+
];
155+
}
156+
}

app/code/Magento/Catalog/Ui/Component/ColumnFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\Catalog\Ui\Component;
77

8+
use Magento\Ui\Component\Filters\FilterModifier;
9+
810
/**
911
* Column Factory
1012
*
@@ -60,13 +62,15 @@ public function __construct(\Magento\Framework\View\Element\UiComponentFactory $
6062
*/
6163
public function create($attribute, $context, array $config = [])
6264
{
65+
$filterModifiers = $context->getRequestParam(FilterModifier::FILTER_MODIFIER, []);
66+
6367
$columnName = $attribute->getAttributeCode();
6468
$config = array_merge([
6569
'label' => __($attribute->getDefaultFrontendLabel()),
6670
'dataType' => $this->getDataType($attribute),
6771
'add_field' => true,
6872
'visible' => $attribute->getIsVisibleInGrid(),
69-
'filter' => ($attribute->getIsFilterableInGrid())
73+
'filter' => ($attribute->getIsFilterableInGrid() || array_key_exists($columnName, $filterModifiers))
7074
? $this->getFilterType($attribute->getFrontendInput())
7175
: null,
7276
], $config);

app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,26 @@
77
*/
88
namespace Magento\ConfigurableProduct\Model\Product\Type\Configurable;
99

10+
use Magento\Catalog\Model\Product;
11+
12+
/**
13+
* Class Price for configurable product
14+
*/
1015
class Price extends \Magento\Catalog\Model\Product\Type\Price
1116
{
1217
/**
13-
* Get product final price
14-
*
15-
* @param float $qty
16-
* @param \Magento\Catalog\Model\Product $product
17-
* @return float
18+
* @inheritdoc
1819
*/
1920
public function getFinalPrice($qty, $product)
2021
{
2122
if ($qty === null && $product->getCalculatedFinalPrice() !== null) {
2223
return $product->getCalculatedFinalPrice();
2324
}
2425
if ($product->getCustomOption('simple_product') && $product->getCustomOption('simple_product')->getProduct()) {
25-
$finalPrice = parent::getFinalPrice($qty, $product->getCustomOption('simple_product')->getProduct());
26+
/** @var Product $simpleProduct */
27+
$simpleProduct = $product->getCustomOption('simple_product')->getProduct();
28+
$simpleProduct->setCustomerGroupId($product->getCustomerGroupId());
29+
$finalPrice = parent::getFinalPrice($qty, $simpleProduct);
2630
} else {
2731
$priceInfo = $product->getPriceInfo();
2832
$finalPrice = $priceInfo->getPrice('final_price')->getAmount()->getValue();
@@ -35,7 +39,7 @@ public function getFinalPrice($qty, $product)
3539
}
3640

3741
/**
38-
* {@inheritdoc}
42+
* @inheritdoc
3943
*/
4044
public function getPrice($product)
4145
{
@@ -48,6 +52,7 @@ public function getPrice($product)
4852
}
4953
}
5054
}
55+
5156
return 0;
5257
}
5358
}

app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Configurable/PriceTest.php

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,52 +6,77 @@
66

77
namespace Magento\ConfigurableProduct\Test\Unit\Model\Product\Type\Configurable;
88

9+
use Magento\Catalog\Model\Product;
10+
use Magento\Catalog\Model\Product\Configuration\Item\Option;
11+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Price as ConfigurablePrice;
12+
use Magento\Framework\Event\ManagerInterface;
13+
use Magento\Framework\Pricing\Amount\AmountInterface;
14+
use Magento\Framework\Pricing\Price\PriceInterface;
15+
use Magento\Framework\Pricing\PriceInfo\Base as PriceInfoBase;
916
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
17+
use PHPUnit\Framework\MockObject\MockObject;
1018

1119
class PriceTest extends \PHPUnit\Framework\TestCase
1220
{
13-
/** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Price */
21+
/**
22+
* @var ObjectManagerHelper
23+
*/
24+
protected $objectManagerHelper;
25+
26+
/**
27+
* @var ConfigurablePrice
28+
*/
1429
protected $model;
1530

16-
/** @var ObjectManagerHelper */
17-
protected $objectManagerHelper;
31+
/**
32+
* @var ManagerInterface|MockObject
33+
*/
34+
private $eventManagerMock;
1835

36+
/**
37+
* @inheritdoc
38+
*/
1939
protected function setUp()
2040
{
2141
$this->objectManagerHelper = new ObjectManagerHelper($this);
2242

43+
$this->eventManagerMock = $this->createPartialMock(
44+
ManagerInterface::class,
45+
['dispatch']
46+
);
2347
$this->model = $this->objectManagerHelper->getObject(
24-
\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Price::class
48+
ConfigurablePrice::class,
49+
['eventManager' => $this->eventManagerMock]
2550
);
2651
}
2752

2853
public function testGetFinalPrice()
2954
{
3055
$finalPrice = 10;
3156
$qty = 1;
32-
$configurableProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
33-
->disableOriginalConstructor()
34-
->setMethods(['getCustomOption', 'getPriceInfo', 'setFinalPrice', '__wakeUp'])
35-
->getMock();
36-
$customOption = $this->getMockBuilder(\Magento\Catalog\Model\Product\Configuration\Item\Option::class)
57+
58+
/** @var Product|MockObject $configurableProduct */
59+
$configurableProduct = $this->getMockBuilder(Product::class)
3760
->disableOriginalConstructor()
38-
->setMethods(['getProduct'])
61+
->setMethods(['getCustomOption', 'getPriceInfo', 'setFinalPrice'])
3962
->getMock();
40-
$priceInfo = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class)
63+
/** @var PriceInfoBase|MockObject $priceInfo */
64+
$priceInfo = $this->getMockBuilder(PriceInfoBase::class)
4165
->disableOriginalConstructor()
4266
->setMethods(['getPrice'])
4367
->getMock();
44-
$price = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class)
68+
/** @var PriceInterface|MockObject $price */
69+
$price = $this->getMockBuilder(PriceInterface::class)
4570
->disableOriginalConstructor()
4671
->getMock();
47-
$amount = $this->getMockBuilder(\Magento\Framework\Pricing\Amount\AmountInterface::class)
72+
/** @var AmountInterface|MockObject $amount */
73+
$amount = $this->getMockBuilder(AmountInterface::class)
4874
->disableOriginalConstructor()
4975
->getMock();
5076

5177
$configurableProduct->expects($this->any())
5278
->method('getCustomOption')
5379
->willReturnMap([['simple_product', false], ['option_ids', false]]);
54-
$customOption->expects($this->never())->method('getProduct');
5580
$configurableProduct->expects($this->once())->method('getPriceInfo')->willReturn($priceInfo);
5681
$priceInfo->expects($this->once())->method('getPrice')->with('final_price')->willReturn($price);
5782
$price->expects($this->once())->method('getAmount')->willReturn($amount);
@@ -60,4 +85,60 @@ public function testGetFinalPrice()
6085

6186
$this->assertEquals($finalPrice, $this->model->getFinalPrice($qty, $configurableProduct));
6287
}
88+
89+
public function testGetFinalPriceWithSimpleProduct()
90+
{
91+
$finalPrice = 10;
92+
$qty = 1;
93+
$customerGroupId = 1;
94+
95+
/** @var Product|MockObject $configurableProduct */
96+
$configurableProduct = $this->createPartialMock(
97+
Product::class,
98+
['getCustomOption', 'setFinalPrice', 'getCustomerGroupId']
99+
);
100+
/** @var Option|MockObject $customOption */
101+
$customOption = $this->createPartialMock(
102+
Option::class,
103+
['getProduct']
104+
);
105+
/** @var Product|MockObject $simpleProduct */
106+
$simpleProduct = $this->createPartialMock(
107+
Product::class,
108+
['setCustomerGroupId', 'setFinalPrice', 'getPrice', 'getTierPrice', 'getData', 'getCustomOption']
109+
);
110+
111+
$configurableProduct->method('getCustomOption')
112+
->willReturnMap([
113+
['simple_product', $customOption],
114+
['option_ids', false]
115+
]);
116+
$configurableProduct->method('getCustomerGroupId')->willReturn($customerGroupId);
117+
$configurableProduct->expects($this->atLeastOnce())
118+
->method('setFinalPrice')
119+
->with($finalPrice)
120+
->willReturnSelf();
121+
$customOption->method('getProduct')->willReturn($simpleProduct);
122+
$simpleProduct->expects($this->atLeastOnce())
123+
->method('setCustomerGroupId')
124+
->with($customerGroupId)
125+
->willReturnSelf();
126+
$simpleProduct->method('getPrice')->willReturn($finalPrice);
127+
$simpleProduct->method('getTierPrice')->with($qty)->willReturn($finalPrice);
128+
$simpleProduct->expects($this->atLeastOnce())
129+
->method('setFinalPrice')
130+
->with($finalPrice)
131+
->willReturnSelf();
132+
$simpleProduct->method('getData')->with('final_price')->willReturn($finalPrice);
133+
$simpleProduct->method('getCustomOption')->with('option_ids')->willReturn(false);
134+
$this->eventManagerMock->expects($this->once())
135+
->method('dispatch')
136+
->with('catalog_product_get_final_price', ['product' => $simpleProduct, 'qty' => $qty]);
137+
138+
$this->assertEquals(
139+
$finalPrice,
140+
$this->model->getFinalPrice($qty, $configurableProduct),
141+
'The final price calculation is wrong'
142+
);
143+
}
63144
}

0 commit comments

Comments
 (0)