Skip to content

Commit b9c9449

Browse files
author
Yaroslav Onischenko
authored
Merge pull request #632 from magento-dragons/dragons-pr-2.1
[DRAGONS] Bugfixes for 2.1.3
2 parents ec5a7f5 + 25fb122 commit b9c9449

File tree

10 files changed

+588
-95
lines changed

10 files changed

+588
-95
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Catalog\Model\Product\Pricing\Renderer;
8+
9+
/**
10+
* Resolver provided to check is product available for sale
11+
*/
12+
class SalableResolver implements SalableResolverInterface
13+
{
14+
/**
15+
* Check is product available for sale
16+
*
17+
* @param \Magento\Framework\Pricing\SaleableInterface $salableItem
18+
* @return boolean
19+
*/
20+
public function isSalable(\Magento\Framework\Pricing\SaleableInterface $salableItem)
21+
{
22+
return $salableItem->getCanShowPrice() !== false && $salableItem->isSalable();
23+
}
24+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Catalog\Model\Product\Pricing\Renderer;
8+
9+
/**
10+
* Interface resolver provided to check is product available for sale
11+
*/
12+
interface SalableResolverInterface
13+
{
14+
/**
15+
* Check is product available for sale
16+
*
17+
* @param \Magento\Framework\Pricing\SaleableInterface $salableItem
18+
* @return boolean
19+
*/
20+
public function isSalable(\Magento\Framework\Pricing\SaleableInterface $salableItem);
21+
}

app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
use Magento\Framework\Pricing\Render;
1111
use Magento\Framework\Pricing\Render\PriceBox as BasePriceBox;
1212
use Magento\Msrp\Pricing\Price\MsrpPrice;
13+
use Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface;
14+
use Magento\Framework\View\Element\Template\Context;
15+
use Magento\Framework\Pricing\SaleableInterface;
16+
use Magento\Framework\Pricing\Price\PriceInterface;
17+
use Magento\Framework\Pricing\Render\RendererPool;
1318

1419
/**
1520
* Class for final_price rendering
@@ -19,12 +24,38 @@
1924
*/
2025
class FinalPriceBox extends BasePriceBox
2126
{
27+
/**
28+
* @var SalableResolverInterface
29+
*/
30+
private $salableResolver;
31+
32+
/**
33+
* @param Context $context
34+
* @param SaleableInterface $saleableItem
35+
* @param PriceInterface $price
36+
* @param RendererPool $rendererPool
37+
* @param array $data
38+
* @param SalableResolverInterface $salableResolver
39+
*/
40+
public function __construct(
41+
Context $context,
42+
SaleableInterface $saleableItem,
43+
PriceInterface $price,
44+
RendererPool $rendererPool,
45+
array $data = [],
46+
SalableResolverInterface $salableResolver = null
47+
) {
48+
parent::__construct($context, $saleableItem, $price, $rendererPool, $data);
49+
$this->salableResolver = $salableResolver ?: \Magento\Framework\App\ObjectManager::getInstance()
50+
->get(SalableResolverInterface::class);
51+
}
52+
2253
/**
2354
* @return string
2455
*/
2556
protected function _toHtml()
2657
{
27-
if (!$this->getSaleableItem() || $this->getSaleableItem()->getCanShowPrice() === false) {
58+
if (!$this->salableResolver->isSalable($this->getSaleableItem())) {
2859
return '';
2960
}
3061

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Catalog\Test\Unit\Model\Product\Pricing\Renderer;
8+
9+
class SalableResolverTest extends \PHPUnit_Framework_TestCase
10+
{
11+
/**
12+
* @var \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver
13+
*/
14+
protected $object;
15+
16+
/**
17+
* @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject
18+
*/
19+
protected $product;
20+
21+
protected function setUp()
22+
{
23+
$this->product = $this->getMock(
24+
\Magento\Catalog\Model\Product::class,
25+
['__wakeup', 'getCanShowPrice', 'isSalable'],
26+
[],
27+
'',
28+
false
29+
);
30+
31+
$objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
32+
$this->object = $objectManager->getObject(
33+
\Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver::class
34+
);
35+
}
36+
37+
public function testSalableItem()
38+
{
39+
$this->product->expects($this->any())
40+
->method('getCanShowPrice')
41+
->willReturn(true);
42+
43+
$this->product->expects($this->any())->method('isSalable')->willReturn(true);
44+
45+
$result = $this->object->isSalable($this->product);
46+
$this->assertTrue($result);
47+
}
48+
49+
public function testNotSalableItem()
50+
{
51+
$this->product->expects($this->any())
52+
->method('getCanShowPrice')
53+
->willReturn(true);
54+
55+
$this->product->expects($this->any())->method('isSalable')->willReturn(false);
56+
57+
$result = $this->object->isSalable($this->product);
58+
$this->assertFalse($result);
59+
}
60+
}

app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
namespace Magento\Catalog\Test\Unit\Pricing\Render;
88

9+
use Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface;
10+
911
/**
1012
* Class FinalPriceBoxTest
1113
*/
@@ -56,11 +58,16 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
5658
*/
5759
protected $price;
5860

61+
/**
62+
* @var SalableResolverInterface|\PHPUnit_Framework_MockObject_MockObject
63+
*/
64+
private $salableResolverMock;
65+
5966
protected function setUp()
6067
{
6168
$this->product = $this->getMock(
62-
'Magento\Catalog\Model\Product',
63-
['getPriceInfo', '__wakeup', 'getCanShowPrice'],
69+
\Magento\Catalog\Model\Product::class,
70+
['getPriceInfo', '__wakeup', 'getCanShowPrice', 'isSalable'],
6471
[],
6572
'',
6673
false
@@ -77,9 +84,7 @@ protected function setUp()
7784
$this->priceBox = $this->getMock('Magento\Framework\Pricing\Render\PriceBox', [], [], '', false);
7885
$this->logger = $this->getMock('Psr\Log\LoggerInterface');
7986

80-
$this->layout->expects($this->any())
81-
->method('getBlock')
82-
->will($this->returnValue($this->priceBox));
87+
$this->layout->expects($this->any())->method('getBlock')->willReturn($this->priceBox);
8388

8489
$cacheState = $this->getMockBuilder(\Magento\Framework\App\Cache\StateInterface::class)
8590
->getMockForAbstractClass();
@@ -92,13 +97,10 @@ protected function setUp()
9297
->disableOriginalConstructor()
9398
->getMock();
9499

95-
$urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class)
96-
->getMockForAbstractClass();
100+
$urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class)->getMockForAbstractClass();
97101

98-
$store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
99-
->getMockForAbstractClass();
100-
101-
$storeManager = $this->getMockBuilder('\Magento\Store\Model\StoreManagerInterface')
102+
$store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)->getMockForAbstractClass();
103+
$storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
102104
->setMethods(['getStore', 'getCode'])
103105
->getMockForAbstractClass();
104106
$storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store));
@@ -146,14 +148,19 @@ protected function setUp()
146148
->will($this->returnValue(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE));
147149

148150
$objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
151+
$this->salableResolverMock = $this->getMockBuilder(SalableResolverInterface::class)
152+
->disableOriginalConstructor()
153+
->getMockForAbstractClass();
154+
149155
$this->object = $objectManager->getObject(
150156
'Magento\Catalog\Pricing\Render\FinalPriceBox',
151157
[
152158
'context' => $context,
153159
'saleableItem' => $this->product,
154160
'rendererPool' => $this->rendererPool,
155161
'price' => $this->price,
156-
'data' => ['zone' => 'test_zone', 'list_category_page' => true]
162+
'data' => ['zone' => 'test_zone', 'list_category_page' => true],
163+
'salableResolver' => $this->salableResolverMock
157164
]
158165
);
159166
}
@@ -171,6 +178,8 @@ public function testRenderMsrpDisabled()
171178
->with($this->equalTo($this->product))
172179
->will($this->returnValue(false));
173180

181+
$this->salableResolverMock->expects($this->once())->method('isSalable')->with($this->product)->willReturn(true);
182+
174183
$result = $this->object->toHtml();
175184

176185
//assert price wrapper
@@ -179,6 +188,18 @@ public function testRenderMsrpDisabled()
179188
$this->assertRegExp('/[final_price]/', $result);
180189
}
181190

191+
public function testNotSalableItem()
192+
{
193+
$this->salableResolverMock
194+
->expects($this->once())
195+
->method('isSalable')
196+
->with($this->product)
197+
->willReturn(false);
198+
$result = $this->object->toHtml();
199+
200+
$this->assertEmpty($result);
201+
}
202+
182203
public function testRenderMsrpEnabled()
183204
{
184205
$priceType = $this->getMock('Magento\Msrp\Pricing\Price\MsrpPrice', [], [], '', false);
@@ -213,6 +234,8 @@ public function testRenderMsrpEnabled()
213234
->with('msrp_price', $this->product, $arguments)
214235
->will($this->returnValue($priceBoxRender));
215236

237+
$this->salableResolverMock->expects($this->once())->method('isSalable')->with($this->product)->willReturn(true);
238+
216239
$result = $this->object->toHtml();
217240

218241
//assert price wrapper
@@ -232,6 +255,8 @@ public function testRenderMsrpNotRegisteredException()
232255
->with($this->equalTo('msrp_price'))
233256
->will($this->throwException(new \InvalidArgumentException()));
234257

258+
$this->salableResolverMock->expects($this->once())->method('isSalable')->with($this->product)->willReturn(true);
259+
235260
$result = $this->object->toHtml();
236261

237262
//assert price wrapper

app/code/Magento/Catalog/etc/di.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<preference for="Magento\Catalog\Api\AttributeSetRepositoryInterface" type="Magento\Catalog\Model\Product\Attribute\SetRepository" />
4545
<preference for="Magento\Catalog\Api\ProductManagementInterface" type="Magento\Catalog\Model\ProductManagement" />
4646
<preference for="Magento\Catalog\Api\AttributeSetFinderInterface" type="Magento\Catalog\Model\Product\Attribute\AttributeSetFinder" />
47+
<preference for="Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface" type="Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver"/>
4748
<type name="Magento\Customer\Model\ResourceModel\Visitor">
4849
<plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
4950
</type>
@@ -615,7 +616,7 @@
615616
</arguments>
616617
</type>
617618
<type name="Magento\Eav\Model\EavCustomAttributeTypeLocator">
618-
<arguments>
619+
<arguments>
619620
<argument name="serviceEntityTypeMap" xsi:type="array">
620621
<item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="const">Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE</item>
621622
</argument>

app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ public function __construct(
5353

5454
/**
5555
* @param \Magento\Framework\Pricing\SaleableInterface|\Magento\Catalog\Model\Product $product
56-
* @return float
57-
* @throws \Magento\Framework\Exception\LocalizedException
56+
* @return float|null
5857
*/
5958
public function resolvePrice(\Magento\Framework\Pricing\SaleableInterface $product)
6059
{
@@ -64,12 +63,7 @@ public function resolvePrice(\Magento\Framework\Pricing\SaleableInterface $produ
6463
$productPrice = $this->priceResolver->resolvePrice($subProduct);
6564
$price = $price ? min($price, $productPrice) : $productPrice;
6665
}
67-
if ($price === null) {
68-
throw new \Magento\Framework\Exception\LocalizedException(
69-
__('Configurable product "%1" does not have sub-products', $product->getSku())
70-
);
71-
}
7266

73-
return (float)$price;
67+
return $price === null ? null : (float)$price;
7468
}
7569
}

app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Price/ConfigurablePriceResolverTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,18 @@ protected function setUp()
5353

5454
/**
5555
* situation: There are no used products, thus there are no prices
56-
*
57-
* @expectedException \Magento\Framework\Exception\LocalizedException
5856
*/
5957
public function testResolvePriceWithNoPrices()
6058
{
6159
$product = $this->getMockBuilder(
6260
\Magento\Catalog\Model\Product::class
6361
)->disableOriginalConstructor()->getMock();
6462

65-
$product->expects($this->once())->method('getSku')->willReturn('Kiwi');
63+
$product->expects($this->never())->method('getSku');
6664

6765
$this->lowestPriceOptionsProvider->expects($this->once())->method('getProducts')->willReturn([]);
6866

69-
$this->resolver->resolvePrice($product);
67+
$this->assertNull($this->resolver->resolvePrice($product));
7068
}
7169

7270
/**

0 commit comments

Comments
 (0)