Skip to content

Commit 64d3e2e

Browse files
committed
Merge remote-tracking branch 'origin/MC-37719' into 2.4-develop-pr127
2 parents a934a1b + d300a16 commit 64d3e2e

File tree

6 files changed

+234
-6
lines changed

6 files changed

+234
-6
lines changed

app/code/Magento/Bundle/Model/LinkManagement.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ public function addChild(
367367
throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
368368
}
369369

370-
return $selectionModel->getId();
370+
return (int)$selectionModel->getId();
371371
}
372372

373373
/**
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Bundle\Plugin\Api\ProductLinkManagement;
10+
11+
use Magento\Bundle\Api\ProductLinkManagementInterface;
12+
use Magento\Catalog\Api\ProductRepositoryInterface;
13+
use Magento\Catalog\Model\Indexer\Product\Full;
14+
15+
/**
16+
* Reindex bundle product after child has been added.
17+
*/
18+
class ReindexAfterAddChildBySkuPlugin
19+
{
20+
/**
21+
* @var Full
22+
*/
23+
private $indexer;
24+
25+
/**
26+
* @var ProductRepositoryInterface
27+
*/
28+
private $productRepository;
29+
30+
/**
31+
* @param Full $indexer
32+
* @param ProductRepositoryInterface $productRepository
33+
*/
34+
public function __construct(Full $indexer, ProductRepositoryInterface $productRepository)
35+
{
36+
$this->indexer = $indexer;
37+
$this->productRepository = $productRepository;
38+
}
39+
40+
/**
41+
* Reindex bundle product after child has been added.
42+
*
43+
* @param ProductLinkManagementInterface $subject
44+
* @param int $result
45+
* @param string $sku
46+
* @return int
47+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
48+
*/
49+
public function afterAddChildByProductSku(
50+
ProductLinkManagementInterface $subject,
51+
int $result,
52+
string $sku
53+
): int {
54+
$bundleProduct = $this->productRepository->get($sku, true);
55+
$this->indexer->executeRow($bundleProduct->getId());
56+
57+
return $result;
58+
}
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Magento\Bundle\Plugin\Api\ProductLinkManagement;
10+
11+
use Magento\Bundle\Api\ProductLinkManagementInterface;
12+
use Magento\Catalog\Api\ProductRepositoryInterface;
13+
use Magento\Catalog\Model\Indexer\Product\Full;
14+
15+
/**
16+
* Reindex bundle product after child has been removed.
17+
*/
18+
class ReindexAfterRemoveChildPlugin
19+
{
20+
/**
21+
* @var Full
22+
*/
23+
private $indexer;
24+
25+
/**
26+
* @var ProductRepositoryInterface
27+
*/
28+
private $productRepository;
29+
30+
/**
31+
* @param Full $indexer
32+
* @param ProductRepositoryInterface $productRepository
33+
*/
34+
public function __construct(Full $indexer, ProductRepositoryInterface $productRepository)
35+
{
36+
$this->indexer = $indexer;
37+
$this->productRepository = $productRepository;
38+
}
39+
40+
/**
41+
* Reindex bundle product after child has been removed.
42+
*
43+
* @param ProductLinkManagementInterface $subject
44+
* @param bool $result
45+
* @param string $sku
46+
* @return bool
47+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
48+
*/
49+
public function afterRemoveChild(
50+
ProductLinkManagementInterface $subject,
51+
bool $result,
52+
string $sku
53+
): bool {
54+
$bundleProduct = $this->productRepository->get($sku, true);
55+
$this->indexer->executeRow($bundleProduct->getId());
56+
57+
return $result;
58+
}
59+
}

app/code/Magento/Bundle/etc/webapi_rest/di.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
</argument>
1414
</arguments>
1515
</type>
16+
<type name="Magento\Bundle\Api\ProductLinkManagementInterface">
17+
<plugin name="reindex_after_add_child_by_sku" type="Magento\Bundle\Plugin\Api\ProductLinkManagement\ReindexAfterAddChildBySkuPlugin"/>
18+
<plugin name="reindex_after_remove_child" type="Magento\Bundle\Plugin\Api\ProductLinkManagement\ReindexAfterRemoveChildPlugin"/>
19+
</type>
1620
</config>

app/code/Magento/Bundle/etc/webapi_soap/di.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
</argument>
1414
</arguments>
1515
</type>
16+
<type name="Magento\Bundle\Api\ProductLinkManagementInterface">
17+
<plugin name="reindex_after_add_child_by_sku" type="Magento\Bundle\Plugin\Api\ProductLinkManagement\ReindexAfterAddChildBySkuPlugin"/>
18+
<plugin name="reindex_after_remove_child" type="Magento\Bundle\Plugin\Api\ProductLinkManagement\ReindexAfterRemoveChildPlugin"/>
19+
</type>
1620
</config>

dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductLinkManagementTest.php

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
* Copyright © Magento, Inc. All rights reserved.
55
* See COPYING.txt for license details.
66
*/
7+
78
namespace Magento\Bundle\Api;
89

10+
use Magento\Framework\Webapi\Rest\Request;
911
use Magento\TestFramework\Helper\Bootstrap;
12+
use Magento\TestFramework\TestCase\WebapiAbstract;
1013

11-
class ProductLinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract
14+
class ProductLinkManagementTest extends WebapiAbstract
1215
{
1316
const SERVICE_NAME = 'bundleProductLinkManagementV1';
1417
const SERVICE_VERSION = 'V1';
@@ -84,6 +87,59 @@ public function testAddChild()
8487
$this->assertGreaterThan(0, $childId);
8588
}
8689

90+
/**
91+
* Verify empty out of stock bundle product is in stock after child has been added.
92+
*
93+
* @magentoApiDataFixture Magento/Bundle/_files/empty_bundle_product.php
94+
* @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php
95+
*
96+
* @return void
97+
*/
98+
public function testBundleProductIsInStockAfterAddChild(): void
99+
{
100+
$productSku = 'bundle-product';
101+
$option = [
102+
'required' => 1,
103+
'position' => 0,
104+
'type' => 'select',
105+
'title' => 'option 1',
106+
'sku' => $productSku,
107+
];
108+
self::assertFalse($this->isProductInStock($productSku));
109+
$optionId = $this->addOption($option);
110+
$linkedProduct = [
111+
'sku' => 'virtual-product',
112+
'option_id' => $optionId,
113+
'position' => '1',
114+
'is_default' => 1,
115+
'priceType' => 2,
116+
'price' => 151.34,
117+
'qty' => 8,
118+
'can_change_quantity' => 1,
119+
];
120+
121+
$this->addChild($productSku, $optionId, $linkedProduct);
122+
self::assertTrue($this->isProductInStock($productSku));
123+
}
124+
125+
/**
126+
* Verify in stock bundle product is out stock after child has been removed.
127+
*
128+
* @magentoApiDataFixture Magento/Bundle/_files/product.php
129+
*
130+
* @return void
131+
*/
132+
public function testBundleProductIsOutOfStockAfterRemoveChild(): void
133+
{
134+
$productSku = 'bundle-product';
135+
$childSku = 'simple';
136+
$optionIds = $this->getProductOptions(3);
137+
$optionId = array_shift($optionIds);
138+
self::assertTrue($this->isProductInStock($productSku));
139+
$this->removeChild($productSku, $optionId, $childSku);
140+
self::assertFalse($this->isProductInStock($productSku));
141+
}
142+
87143
/**
88144
* @magentoApiDataFixture Magento/Bundle/_files/product.php
89145
* @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php
@@ -119,7 +175,7 @@ private function saveChild($productSku, $linkedProduct)
119175
[$productSku, $linkedProduct['id']],
120176
$resourcePath
121177
),
122-
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
178+
'httpMethod' => Request::HTTP_METHOD_PUT,
123179
],
124180
'soap' => [
125181
'service' => self::SERVICE_NAME,
@@ -149,7 +205,7 @@ private function addChild($productSku, $optionId, $linkedProduct)
149205
[$productSku, $optionId],
150206
$resourcePath
151207
),
152-
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
208+
'httpMethod' => Request::HTTP_METHOD_POST,
153209
],
154210
'soap' => [
155211
'service' => self::SERVICE_NAME,
@@ -179,7 +235,7 @@ protected function removeChild($productSku, $optionId, $childSku)
179235
$serviceInfo = [
180236
'rest' => [
181237
'resourcePath' => sprintf($resourcePath, $productSku, $optionId, $childSku),
182-
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE,
238+
'httpMethod' => Request::HTTP_METHOD_DELETE,
183239
],
184240
'soap' => [
185241
'service' => self::SERVICE_NAME,
@@ -200,7 +256,7 @@ protected function getChildren($productSku)
200256
$serviceInfo = [
201257
'rest' => [
202258
'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/children',
203-
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
259+
'httpMethod' => Request::HTTP_METHOD_GET,
204260
],
205261
'soap' => [
206262
'service' => self::SERVICE_NAME,
@@ -210,4 +266,50 @@ protected function getChildren($productSku)
210266
];
211267
return $this->_webApiCall($serviceInfo, ['productSku' => $productSku]);
212268
}
269+
270+
/**
271+
* Check product stock status.
272+
*
273+
* @param string $productSku
274+
* @return bool
275+
*/
276+
private function isProductInStock(string $productSku): bool
277+
{
278+
$serviceInfo = [
279+
'rest' => [
280+
'resourcePath' => '/V1/stockStatuses/' . $productSku,
281+
'httpMethod' => Request::HTTP_METHOD_GET,
282+
],
283+
'soap' => [
284+
'service' => 'catalogInventoryStockRegistryV1',
285+
'serviceVersion' => self::SERVICE_VERSION,
286+
'operation' => 'catalogInventoryStockRegistryV1getStockStatusBySku',
287+
],
288+
];
289+
$result = $this->_webApiCall($serviceInfo, ['productSku' => $productSku]);
290+
291+
return (bool)$result['stock_status'];
292+
}
293+
294+
/**
295+
* Add option to bundle product.
296+
*
297+
* @param array $option
298+
* @return int
299+
*/
300+
private function addOption(array $option): int
301+
{
302+
$serviceInfo = [
303+
'rest' => [
304+
'resourcePath' => '/V1/bundle-products/options/add',
305+
'httpMethod' => Request::HTTP_METHOD_POST,
306+
],
307+
'soap' => [
308+
'service' => 'bundleProductOptionManagementV1',
309+
'serviceVersion' => self::SERVICE_VERSION,
310+
'operation' => 'bundleProductOptionManagementV1Save',
311+
],
312+
];
313+
return $this->_webApiCall($serviceInfo, ['option' => $option]);
314+
}
213315
}

0 commit comments

Comments
 (0)