Skip to content

Commit e1211b6

Browse files
authored
Merge pull request #4718 from magento-chaika/Chaika-PR-2019-09-01-2.2
Chaika-PR-2019-09-01-2.2
2 parents d317cd4 + 60284ae commit e1211b6

File tree

11 files changed

+181
-58
lines changed

11 files changed

+181
-58
lines changed

app/code/Magento/Bundle/Model/ResourceModel/Option/Collection.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\Bundle\Model\ResourceModel\Option;
77

8+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
9+
810
/**
911
* Bundle Options Resource Collection
1012
* @api
@@ -138,12 +140,10 @@ public function setPositionOrder()
138140

139141
/**
140142
* Append selection to options
141-
* stripBefore - indicates to reload
142-
* appendAll - indicates do we need to filter by saleable and required custom options
143143
*
144144
* @param \Magento\Bundle\Model\ResourceModel\Selection\Collection $selectionsCollection
145-
* @param bool $stripBefore
146-
* @param bool $appendAll
145+
* @param bool $stripBefore indicates to reload
146+
* @param bool $appendAll indicates do we need to filter by saleable and required custom options
147147
* @return \Magento\Framework\DataObject[]
148148
*/
149149
public function appendSelections($selectionsCollection, $stripBefore = false, $appendAll = true)
@@ -156,7 +156,9 @@ public function appendSelections($selectionsCollection, $stripBefore = false, $a
156156
foreach ($selectionsCollection->getItems() as $key => $selection) {
157157
$option = $this->getItemById($selection->getOptionId());
158158
if ($option) {
159-
if ($appendAll || $selection->isSalable() && !$selection->getRequiredOptions()) {
159+
if ($appendAll ||
160+
((int) $selection->getStatus()) === Status::STATUS_ENABLED && !$selection->getRequiredOptions()
161+
) {
160162
$selection->setOption($option);
161163
$option->addSelection($selection);
162164
} else {

app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
namespace Magento\ConfigurableProduct\Block\Product\View\Type;
99

10+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
1011
use Magento\ConfigurableProduct\Model\ConfigurableAttributeData;
1112
use Magento\Customer\Helper\Session\CurrentCustomer;
1213
use Magento\Customer\Model\Session;
@@ -183,8 +184,9 @@ public function getAllowProducts()
183184
$products = [];
184185
$skipSaleableCheck = $this->catalogProduct->getSkipSaleableCheck();
185186
$allProducts = $this->getProduct()->getTypeInstance()->getUsedProducts($this->getProduct(), null);
187+
/** @var $product \Magento\Catalog\Model\Product */
186188
foreach ($allProducts as $product) {
187-
if ($product->isSaleable() || $skipSaleableCheck) {
189+
if ($skipSaleableCheck || ((int) $product->getStatus()) === Status::STATUS_ENABLED) {
188190
$products[] = $product;
189191
}
190192
}

app/code/Magento/ConfigurableProduct/Helper/Data.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
/**
1212
* Class Data
13+
*
1314
* Helper class for getting options
1415
* @api
1516
* @since 100.0.2
@@ -85,8 +86,9 @@ public function getOptions($currentProduct, $allowedProducts)
8586
$productAttribute = $attribute->getProductAttribute();
8687
$productAttributeId = $productAttribute->getId();
8788
$attributeValue = $product->getData($productAttribute->getAttributeCode());
88-
89-
$options[$productAttributeId][$attributeValue][] = $productId;
89+
if ($product->isSalable()) {
90+
$options[$productAttributeId][$attributeValue][] = $productId;
91+
}
9092
$options['index'][$productId][$productAttributeId] = $attributeValue;
9193
}
9294
}

app/code/Magento/ConfigurableProduct/Plugin/Model/ResourceModel/Attribute/InStockOptionSelectBuilder.php

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Attribute;
77

8+
use Magento\CatalogInventory\Api\StockConfigurationInterface;
89
use Magento\CatalogInventory\Model\ResourceModel\Stock\Status;
910
use Magento\ConfigurableProduct\Model\ResourceModel\Attribute\OptionSelectBuilderInterface;
1011
use Magento\Framework\DB\Select;
@@ -20,13 +21,21 @@ class InStockOptionSelectBuilder
2021
* @var Status
2122
*/
2223
private $stockStatusResource;
23-
24+
/**
25+
* @var StockConfigurationInterface
26+
*/
27+
private $stockConfig;
28+
2429
/**
2530
* @param Status $stockStatusResource
31+
* @param StockConfigurationInterface $stockConfig
2632
*/
27-
public function __construct(Status $stockStatusResource)
28-
{
33+
public function __construct(
34+
Status $stockStatusResource,
35+
StockConfigurationInterface $stockConfig
36+
) {
2937
$this->stockStatusResource = $stockStatusResource;
38+
$this->stockConfig = $stockConfig;
3039
}
3140

3241
/**
@@ -40,14 +49,16 @@ public function __construct(Status $stockStatusResource)
4049
*/
4150
public function afterGetSelect(OptionSelectBuilderInterface $subject, Select $select)
4251
{
43-
$select->joinInner(
44-
['stock' => $this->stockStatusResource->getMainTable()],
45-
'stock.product_id = entity.entity_id',
46-
[]
47-
)->where(
48-
'stock.stock_status = ?',
49-
\Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK
50-
);
52+
if (!$this->stockConfig->isShowOutOfStock()) {
53+
$select->joinInner(
54+
['stock' => $this->stockStatusResource->getMainTable()],
55+
'stock.product_id = entity.entity_id',
56+
[]
57+
)->where(
58+
'stock.stock_status = ?',
59+
\Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK
60+
);
61+
}
5162

5263
return $select;
5364
}

app/code/Magento/ConfigurableProduct/Test/Unit/Helper/DataTest.php

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@ public function testGetOptions(array $expected, array $data)
6969

7070
$this->_imageHelperMock->expects($this->any())
7171
->method('init')
72-
->willReturnMap([
73-
[$data['current_product_mock'], 'product_page_image_large', [], $imageHelper1],
74-
[$data['allowed_products'][0], 'product_page_image_large', [], $imageHelper1],
75-
[$data['allowed_products'][1], 'product_page_image_large', [], $imageHelper2],
76-
]);
72+
->willReturnMap(
73+
[
74+
[$data['current_product_mock'], 'product_page_image_large', [], $imageHelper1],
75+
[$data['allowed_products'][0], 'product_page_image_large', [], $imageHelper1],
76+
[$data['allowed_products'][1], 'product_page_image_large', [], $imageHelper2],
77+
]
78+
);
7779
}
7880

7981
$this->assertEquals(
@@ -130,14 +132,18 @@ public function getOptionsDataProvider()
130132
for ($i = 1; $i <= 2; $i++) {
131133
$productMock = $this->createPartialMock(
132134
\Magento\Catalog\Model\Product::class,
133-
['getData', 'getImage', 'getId', '__wakeup', 'getMediaGalleryImages']
135+
['getData', 'getImage', 'getId', '__wakeup', 'getMediaGalleryImages', 'isSalable']
134136
);
135137
$productMock->expects($this->any())
136138
->method('getData')
137139
->will($this->returnCallback([$this, 'getDataCallback']));
138140
$productMock->expects($this->any())
139141
->method('getId')
140142
->will($this->returnValue('product_id_' . $i));
143+
$productMock
144+
->expects($this->any())
145+
->method('isSalable')
146+
->will($this->returnValue(true));
141147
if ($i == 2) {
142148
$productMock->expects($this->any())
143149
->method('getImage')
@@ -198,11 +204,13 @@ public function testGetGalleryImages()
198204

199205
$this->_imageHelperMock->expects($this->exactly(3))
200206
->method('init')
201-
->willReturnMap([
202-
[$productMock, 'product_page_image_small', [], $this->_imageHelperMock],
203-
[$productMock, 'product_page_image_medium_no_frame', [], $this->_imageHelperMock],
204-
[$productMock, 'product_page_image_large_no_frame', [], $this->_imageHelperMock],
205-
])
207+
->willReturnMap(
208+
[
209+
[$productMock, 'product_page_image_small', [], $this->_imageHelperMock],
210+
[$productMock, 'product_page_image_medium_no_frame', [], $this->_imageHelperMock],
211+
[$productMock, 'product_page_image_large_no_frame', [], $this->_imageHelperMock],
212+
]
213+
)
206214
->willReturnSelf();
207215
$this->_imageHelperMock->expects($this->exactly(3))
208216
->method('setImageFile')
@@ -234,9 +242,9 @@ private function getImagesCollection()
234242
->getMock();
235243

236244
$items = [
237-
new \Magento\Framework\DataObject([
238-
'file' => 'test_file'
239-
]),
245+
new \Magento\Framework\DataObject(
246+
['file' => 'test_file']
247+
),
240248
];
241249

242250
$collectionMock->expects($this->any())

app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ define([
377377
optionFinalPrice,
378378
optionPriceDiff,
379379
optionPrices = this.options.spConfig.optionPrices,
380+
allowedOptions = [],
381+
indexKey,
380382
allowedProductMinPrice;
381383

382384
this._clearSelect(element);
@@ -389,6 +391,13 @@ define([
389391
}
390392

391393
if (options) {
394+
for (indexKey in this.options.spConfig.index) {
395+
/* eslint-disable max-depth */
396+
if (this.options.spConfig.index.hasOwnProperty(indexKey)) {
397+
allowedOptions = allowedOptions.concat(_.values(this.options.spConfig.index[indexKey]));
398+
}
399+
}
400+
392401
for (i = 0; i < options.length; i++) {
393402
allowedProducts = [];
394403
optionPriceDiff = 0;
@@ -421,14 +430,18 @@ define([
421430
}
422431
}
423432

424-
if (allowedProducts.length > 0) {
433+
if (allowedProducts.length > 0 || _.include(allowedOptions, options[i].id)) {
425434
options[i].allowedProducts = allowedProducts;
426435
element.options[index] = new Option(this._getOptionLabel(options[i]), options[i].id);
427436

428437
if (typeof options[i].price !== 'undefined') {
429438
element.options[index].setAttribute('price', options[i].price);
430439
}
431440

441+
if (allowedProducts.length === 0) {
442+
element.options[index].disabled = true;
443+
}
444+
432445
element.options[index].config = options[i];
433446
index++;
434447
}

app/code/Magento/Swatches/Test/Unit/Block/Product/Renderer/ConfigurableTest.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\Swatches\Test\Unit\Block\Product\Renderer;
77

8+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
89
use Magento\Swatches\Block\Product\Renderer\Configurable;
910
use Magento\Swatches\Model\Swatch;
1011

@@ -150,11 +151,13 @@ public function testSetIsProductListingContext()
150151
private function prepareGetJsonSwatchConfig()
151152
{
152153
$product1 = $this->createMock(\Magento\Catalog\Model\Product::class);
153-
$product1->expects($this->atLeastOnce())->method('isSaleable')->willReturn(true);
154+
$product1->expects($this->any())->method('isSaleable')->willReturn(true);
155+
$product1->expects($this->atLeastOnce())->method('getStatus')->willReturn(Status::STATUS_ENABLED);
154156
$product1->expects($this->atLeastOnce())->method('getData')->with('code')->willReturn(1);
155157

156158
$product2 = $this->createMock(\Magento\Catalog\Model\Product::class);
157-
$product2->expects($this->atLeastOnce())->method('isSaleable')->willReturn(true);
159+
$product2->expects($this->any())->method('isSaleable')->willReturn(true);
160+
$product2->expects($this->atLeastOnce())->method('getStatus')->willReturn(Status::STATUS_ENABLED);
158161
$product2->expects($this->atLeastOnce())->method('getData')->with('code')->willReturn(3);
159162

160163
$simpleProducts = [$product1, $product2];

app/code/Magento/Swatches/Test/Unit/Block/Product/Renderer/Listing/ConfigurableTest.php

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\Swatches\Test\Unit\Block\Product\Renderer\Listing;
77

8+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
89
use Magento\Swatches\Block\Product\Renderer\Configurable;
910

1011
/**
@@ -177,14 +178,16 @@ public function testGetJsonSwatchNotUsedInProductListing()
177178
$this->configurable->setProduct($this->product);
178179
$this->swatchHelper->expects($this->once())->method('getSwatchAttributesAsArray')
179180
->with($this->product)
180-
->willReturn([
181-
1 => [
182-
'options' => [1 => 'testA', 3 => 'testB'],
183-
'use_product_image_for_swatch' => true,
184-
'used_in_product_listing' => false,
185-
'attribute_code' => 'code',
186-
],
187-
]);
181+
->willReturn(
182+
[
183+
1 => [
184+
'options' => [1 => 'testA', 3 => 'testB'],
185+
'use_product_image_for_swatch' => true,
186+
'used_in_product_listing' => false,
187+
'attribute_code' => 'code',
188+
],
189+
]
190+
);
188191
$this->swatchHelper->expects($this->once())->method('getSwatchesByOptionsId')
189192
->willReturn([]);
190193
$this->jsonEncoder->expects($this->once())->method('encode')->with([]);
@@ -210,31 +213,33 @@ public function testGetJsonSwatchUsedInProductListing()
210213
$this->configurable->setProduct($this->product);
211214
$this->swatchHelper->expects($this->once())->method('getSwatchAttributesAsArray')
212215
->with($this->product)
213-
->willReturn([
214-
1 => [
215-
'options' => $products,
216-
'use_product_image_for_swatch' => true,
217-
'used_in_product_listing' => true,
218-
'attribute_code' => 'code',
219-
],
220-
]);
216+
->willReturn(
217+
[
218+
1 => [
219+
'options' => $products,
220+
'use_product_image_for_swatch' => true,
221+
'used_in_product_listing' => true,
222+
'attribute_code' => 'code',
223+
],
224+
]
225+
);
221226
$this->swatchHelper->expects($this->once())->method('getSwatchesByOptionsId')
222227
->with([1, 3])
223-
->willReturn([
224-
3 => ['type' => $expected['type'], 'value' => $expected['value']]
225-
]);
228+
->willReturn([3 => ['type' => $expected['type'], 'value' => $expected['value']]]);
226229
$this->jsonEncoder->expects($this->once())->method('encode');
227230
$this->configurable->getJsonSwatchConfig();
228231
}
229232

230233
private function prepareGetJsonSwatchConfig()
231234
{
232235
$product1 = $this->createMock(\Magento\Catalog\Model\Product::class);
233-
$product1->expects($this->atLeastOnce())->method('isSaleable')->willReturn(true);
236+
$product1->expects($this->any())->method('isSaleable')->willReturn(true);
237+
$product1->expects($this->atLeastOnce())->method('getStatus')->willReturn(Status::STATUS_ENABLED);
234238
$product1->expects($this->any())->method('getData')->with('code')->willReturn(1);
235239

236240
$product2 = $this->createMock(\Magento\Catalog\Model\Product::class);
237-
$product2->expects($this->atLeastOnce())->method('isSaleable')->willReturn(true);
241+
$product2->expects($this->any())->method('isSaleable')->willReturn(true);
242+
$product2->expects($this->atLeastOnce())->method('getStatus')->willReturn(Status::STATUS_ENABLED);
238243
$product2->expects($this->any())->method('getData')->with('code')->willReturn(3);
239244

240245
$simpleProducts = [$product1, $product2];

0 commit comments

Comments
 (0)