Skip to content

Commit acdefe4

Browse files
committed
MC-41177: Bundle Items price after saving to 0.00 go back to default price value Bundle Product Edit.
1 parent aaeadff commit acdefe4

File tree

6 files changed

+205
-24
lines changed

6 files changed

+205
-24
lines changed

app/code/Magento/Bundle/Model/Product/LinksList.php

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@
44
* Copyright © Magento, Inc. All rights reserved.
55
* See COPYING.txt for license details.
66
*/
7+
declare(strict_types=1);
8+
79
namespace Magento\Bundle\Model\Product;
810

11+
use Magento\Bundle\Api\Data\LinkInterface;
12+
use Magento\Bundle\Api\Data\LinkInterfaceFactory;
13+
use Magento\Catalog\Api\Data\ProductInterface;
14+
use Magento\Framework\Api\DataObjectHelper;
15+
16+
/**
17+
* Retrieve bundle product links service.
18+
*/
919
class LinksList
1020
{
1121
/**
12-
* @var \Magento\Bundle\Api\Data\LinkInterfaceFactory
22+
* @var LinkInterfaceFactory
1323
*/
1424
protected $linkFactory;
1525

@@ -19,52 +29,52 @@ class LinksList
1929
protected $type;
2030

2131
/**
22-
* @var \Magento\Framework\Api\DataObjectHelper
32+
* @var DataObjectHelper
2333
*/
2434
protected $dataObjectHelper;
2535

2636
/**
27-
* @param \Magento\Bundle\Api\Data\LinkInterfaceFactory $linkFactory
37+
* @param LinkInterfaceFactory $linkFactory
2838
* @param Type $type
29-
* @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper
39+
* @param DataObjectHelper $dataObjectHelper
3040
*/
3141
public function __construct(
32-
\Magento\Bundle\Api\Data\LinkInterfaceFactory $linkFactory,
33-
\Magento\Bundle\Model\Product\Type $type,
34-
\Magento\Framework\Api\DataObjectHelper $dataObjectHelper
42+
LinkInterfaceFactory $linkFactory,
43+
Type $type,
44+
DataObjectHelper $dataObjectHelper
3545
) {
3646
$this->linkFactory = $linkFactory;
3747
$this->type = $type;
3848
$this->dataObjectHelper = $dataObjectHelper;
3949
}
4050

4151
/**
42-
* Bundle Product Items Data
52+
* Get Bundle Product Items Data.
4353
*
44-
* @param \Magento\Catalog\Api\Data\ProductInterface $product
54+
* @param ProductInterface $product
4555
* @param int $optionId
46-
* @return \Magento\Bundle\Api\Data\LinkInterface[]
56+
* @return LinkInterface[]
4757
*/
48-
public function getItems(\Magento\Catalog\Api\Data\ProductInterface $product, $optionId)
58+
public function getItems(ProductInterface $product, $optionId)
4959
{
5060
$selectionCollection = $this->type->getSelectionsCollection([$optionId], $product);
5161

5262
$productLinks = [];
5363
/** @var \Magento\Catalog\Model\Product $selection */
5464
foreach ($selectionCollection as $selection) {
55-
$bundledProductPrice = $selection->getSelectionPriceValue();
56-
if ($bundledProductPrice <= 0) {
57-
$bundledProductPrice = $selection->getPrice();
58-
}
59-
$selectionPriceType = $product->getPriceType() ? $selection->getSelectionPriceType() : null;
60-
$selectionPrice = $bundledProductPrice ? $bundledProductPrice : null;
65+
$priceType = $product->getPriceType();
66+
$selectionPriceType = $priceType ? $selection->getSelectionPriceType() : null;
67+
$selectionPriceValue = $selection->getSelectionPriceValue() < 0
68+
? $selection->getPrice()
69+
: $selection->getSelectionPriceValue();
70+
$selectionPrice = $priceType ? $selectionPriceValue : $selection->getPrice();
6171

62-
/** @var \Magento\Bundle\Api\Data\LinkInterface $productLink */
72+
/** @var LinkInterface $productLink */
6373
$productLink = $this->linkFactory->create();
6474
$this->dataObjectHelper->populateWithArray(
6575
$productLink,
6676
$selection->getData(),
67-
\Magento\Bundle\Api\Data\LinkInterface::class
77+
LinkInterface::class
6878
);
6979
$productLink->setIsDefault($selection->getIsDefault())
7080
->setId($selection->getSelectionId())

app/code/Magento/Bundle/Test/Unit/Model/Product/LinksListTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function testLinksList()
9595
$this->selectionMock->expects($this->once())
9696
->method('getSelectionPriceType')
9797
->willReturn('selection_price_type');
98-
$this->selectionMock->expects($this->once())->method('getSelectionPriceValue')->willReturn(12);
98+
$this->selectionMock->expects($this->exactly(2))->method('getSelectionPriceValue')->willReturn(12);
9999
$this->selectionMock->expects($this->once())->method('getData')->willReturn(['some data']);
100100
$this->selectionMock->expects($this->once())->method('getSelectionId')->willReturn($selectionId);
101101
$this->selectionMock->expects($this->once())->method('getIsDefault')->willReturn(true);

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

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ public function testUpdateBundleAddSelection()
225225
public function testUpdateBundleAddAndDeleteOption()
226226
{
227227
$bundleProduct = $this->createDynamicBundleProduct();
228-
$linkedProductPrice = 20;
229-
230228
$bundleProductOptions = $this->getBundleProductOptions($bundleProduct);
231229

232230
$oldOptionId = $bundleProductOptions[0]['option_id'];
@@ -239,7 +237,7 @@ public function testUpdateBundleAddAndDeleteOption()
239237
[
240238
'sku' => 'simple2',
241239
'qty' => 2,
242-
"price" => $linkedProductPrice,
240+
"price" => 20,
243241
"price_type" => 1,
244242
"is_default" => false,
245243
],
@@ -250,14 +248,51 @@ public function testUpdateBundleAddAndDeleteOption()
250248

251249
$updatedProduct = $this->getProduct(self::BUNDLE_PRODUCT_ID);
252250
$bundleOptions = $this->getBundleProductOptions($updatedProduct);
251+
$simpleProduct = $this->getProduct('simple2');
253252
$this->assertEquals('new option', $bundleOptions[0]['title']);
254253
$this->assertTrue($bundleOptions[0]['required']);
255254
$this->assertEquals('select', $bundleOptions[0]['type']);
256255
$this->assertGreaterThan($oldOptionId, $bundleOptions[0]['option_id']);
257256
$this->assertFalse(isset($bundleOptions[1]));
258257
$this->assertEquals('simple2', $bundleOptions[0]['product_links'][0]['sku']);
259258
$this->assertEquals(2, $bundleOptions[0]['product_links'][0]['qty']);
260-
$this->assertEquals($linkedProductPrice, $bundleOptions[0]['product_links'][0]['price']);
259+
$this->assertEquals($simpleProduct['price'], $bundleOptions[0]['product_links'][0]['price']);
260+
}
261+
262+
/**
263+
* @magentoApiDataFixture Magento/Catalog/_files/products_new.php
264+
* @magentoApiDataFixture Magento/Catalog/_files/second_product_simple.php
265+
*/
266+
public function testUpdateFixedPriceBundleProductOptionSelectionPrice()
267+
{
268+
$optionPrice = 20;
269+
$bundleProduct = $this->createFixedPriceBundleProduct();
270+
$bundleProductOptions = $this->getBundleProductOptions($bundleProduct);
271+
272+
$oldOptionId = $bundleProductOptions[0]['option_id'];
273+
//replace current option with a new option
274+
$bundleProductOptions[0] = [
275+
'title' => 'new option',
276+
'required' => true,
277+
'type' => 'select',
278+
'product_links' => [
279+
[
280+
'sku' => 'simple2',
281+
'qty' => 2,
282+
"price" => $optionPrice,
283+
"price_type" => 1,
284+
"is_default" => false,
285+
],
286+
],
287+
];
288+
$this->setBundleProductOptions($bundleProduct, $bundleProductOptions);
289+
$this->saveProduct($bundleProduct);
290+
291+
$updatedProduct = $this->getProduct(self::BUNDLE_PRODUCT_ID);
292+
$bundleOptions = $this->getBundleProductOptions($updatedProduct);
293+
$this->assertEquals('simple2', $bundleOptions[0]['product_links'][0]['sku']);
294+
$this->assertEquals(2, $bundleOptions[0]['product_links'][0]['qty']);
295+
$this->assertEquals($optionPrice, $bundleOptions[0]['product_links'][0]['price']);
261296
}
262297

263298
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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\Bundle\Model\Product;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\TestFramework\Helper\Bootstrap;
12+
use PHPUnit\Framework\TestCase;
13+
14+
/**
15+
* Test for bundle product linksList model.
16+
*
17+
*/
18+
class LinksListTest extends TestCase
19+
{
20+
/**
21+
* @var LinksList
22+
*/
23+
private $linksList;
24+
25+
/**
26+
* @inheridoc
27+
*/
28+
protected function setUp(): void
29+
{
30+
$this->linksList = Bootstrap::getObjectManager()->get(LinksList::class);
31+
}
32+
33+
/**
34+
* verify get items with zero option selection price.
35+
*
36+
* @magentoDataFixture Magento/Bundle/_files//fixed_bundle_product_zero_price_option_selection.php
37+
* @return void
38+
*/
39+
public function testGetItemsWithZeroPrice(): void
40+
{
41+
$productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
42+
$product = $productRepository->get('bundle_product');
43+
$type = Bootstrap::getObjectManager()->get(Type::class);
44+
$optionsIds = $type->getOptionsIds($product);
45+
$links = $this->linksList->getItems($product, current($optionsIds));
46+
$link = current($links);
47+
self::assertEquals('simple1', $link->getSku());
48+
self::assertEquals(0, $link->getPrice());
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
use Magento\Bundle\Model\Product\Price;
9+
use Magento\Catalog\Api\ProductRepositoryInterface;
10+
use Magento\Catalog\Model\Product;
11+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
12+
use Magento\Catalog\Model\Product\Type;
13+
use Magento\Catalog\Model\Product\Visibility;
14+
use Magento\TestFramework\Bundle\Model\PrepareBundleLinks;
15+
use Magento\TestFramework\Helper\Bootstrap;
16+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
17+
18+
Resolver::getInstance()->requireDataFixture('Magento/Bundle/_files/multiple_products.php');
19+
20+
$objectManager = Bootstrap::getObjectManager();
21+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
22+
$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class);
23+
$product = $objectManager->create(Product::class);
24+
$product->setTypeId(Type::TYPE_BUNDLE)
25+
->setAttributeSetId($product->getDefaultAttributeSetId())
26+
->setWebsiteIds([1])
27+
->setName('Bundle Product')
28+
->setSku('bundle_product')
29+
->setVisibility(Visibility::VISIBILITY_BOTH)
30+
->setStatus(Status::STATUS_ENABLED)
31+
->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
32+
->setPriceView(0)
33+
->setPriceType(Price::PRICE_TYPE_FIXED)
34+
->setPrice(110.0)
35+
->setShipmentType(0);
36+
37+
$optionData = [
38+
[
39+
'title' => 'Test Option',
40+
'default_title' => 'Test Option',
41+
'type' => 'radio',
42+
'required' => 1,
43+
'delete' => '',
44+
],
45+
];
46+
$selectionData = [
47+
[
48+
'sku' => 'simple1',
49+
'selection_qty' => 1,
50+
'selection_price_value' => 0,
51+
'selection_price_type' => 1,
52+
'selection_can_change_qty' => 1,
53+
],
54+
];
55+
$product = $prepareBundleLinks->execute($product, $optionData, [$selectionData]);
56+
$productRepository->save($product);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Framework\Exception\NoSuchEntityException;
10+
use Magento\Framework\Registry;
11+
use Magento\TestFramework\Helper\Bootstrap;
12+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
13+
14+
Resolver::getInstance()->requireDataFixture('Magento/Bundle/_files/multiple_products_rollback.php');
15+
$objectManager = Bootstrap::getObjectManager();
16+
$registry = $objectManager->get(Registry::class);
17+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
18+
19+
$registry->unregister('isSecureArea');
20+
$registry->register('isSecureArea', true);
21+
22+
try {
23+
$product = $productRepository->get('bundle_product', false, null, true);
24+
$productRepository->delete($product);
25+
} catch (NoSuchEntityException $e) {
26+
//Product already removed
27+
}
28+
29+
$registry->unregister('isSecureArea');
30+
$registry->register('isSecureArea', false);

0 commit comments

Comments
 (0)