Skip to content

Commit 9842136

Browse files
committed
MAGETWO-70540: Edit bundle product from shopping cart work unexpected
1 parent 6ba5991 commit 9842136

File tree

11 files changed

+370
-12
lines changed

11 files changed

+370
-12
lines changed

app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option/Multi.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,28 @@ class Multi extends \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Optio
1717
* @var string
1818
*/
1919
protected $_template = 'catalog/product/view/type/bundle/option/multi.phtml';
20+
21+
/**
22+
* @inheritdoc
23+
*/
24+
protected function _getSelectedOptions()
25+
{
26+
if ($this->_selectedOptions === null) {
27+
$this->_selectedOptions = [];
28+
/** @var \Magento\Bundle\Model\Option $option */
29+
$option = $this->getOption();
30+
if ($this->getProduct()->hasPreconfiguredValues()) {
31+
$selectionIds = $this->getProduct()->getPreconfiguredValues()->getData(
32+
'bundle_option/' . $option->getId()
33+
);
34+
foreach ($selectionIds as $selectionId) {
35+
if ($selectionId && $option->getSelectionById($selectionId)) {
36+
$this->_selectedOptions[] = $selectionId;
37+
}
38+
}
39+
}
40+
}
41+
42+
return $this->_selectedOptions;
43+
}
2044
}

app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
$product = $block->getProduct();
1313
$helper = $this->helper('Magento\Catalog\Helper\Output');
1414
?>
15-
<?php $options = $block->decorateArray($block->getOptions()); ?>
15+
<?php $options = $block->decorateArray($block->getOptions($product->getConfigureMode())); ?>
1616
<?php if ($product->isSaleable()):?>
1717
<?php if (count($options)): ?>
1818
<script type="text/x-magento-init">

dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ public function addToCart(BundleProduct $product, CatalogProductView $catalogPro
115115
* Get product options
116116
*
117117
* @param FixtureInterface $product
118+
* @param bool $showSelected
118119
* @return array
119120
* @throws \Exception
120121
*/
121-
public function getOptions(FixtureInterface $product)
122+
public function getOptions(FixtureInterface $product, bool $showSelected = false)
122123
{
123124
/** @var BundleProduct $product */
124125
$this->product = $product;
@@ -139,7 +140,9 @@ public function getOptions(FixtureInterface $product)
139140
$optionElement = $listFormOptions[$title];
140141
$getTypeData = 'get' . $this->optionNameConvert($option['frontend_type']) . 'Data';
141142

142-
$optionData = $this->$getTypeData($optionElement);
143+
$optionData = $showSelected
144+
? $this->$getTypeData($optionElement, $showSelected)
145+
: $this->$getTypeData($optionElement);
143146
$optionData['title'] = $title;
144147
$optionData['type'] = $option['frontend_type'];
145148
$optionData['is_require'] = $optionElement->find($this->required, Locator::SELECTOR_XPATH)->isVisible()
@@ -203,12 +206,13 @@ protected function getDropdownData(SimpleElement $option)
203206
* Get data of "Multiple select" option
204207
*
205208
* @param SimpleElement $option
209+
* @param bool $showSelected
206210
* @return array
207211
*/
208-
protected function getMultipleselectData(SimpleElement $option)
212+
protected function getMultipleselectData(SimpleElement $option, bool $showSelected = false)
209213
{
210214
$multiselect = $option->find($this->selectOption, Locator::SELECTOR_XPATH, 'multiselect');
211-
$data = $this->getSelectOptionsData($multiselect, 1);
215+
$data = $this->getSelectOptionsData($multiselect, 1, $showSelected);
212216

213217
foreach ($data['options'] as $key => $option) {
214218
$option['title'] = trim(preg_replace('/^[\d]+ x/', '', $option['title']));
@@ -261,16 +265,24 @@ protected function getCheckboxData(SimpleElement $option)
261265
*
262266
* @param SimpleElement $element
263267
* @param int $firstOption
268+
* @param bool $showSelected
264269
* @return array
265270
*/
266-
protected function getSelectOptionsData(SimpleElement $element, $firstOption = 1)
271+
protected function getSelectOptionsData(SimpleElement $element, $firstOption = 1, bool $showSelected = false)
267272
{
268273
$listOptions = [];
269274

270275
$count = $firstOption;
271276
$selectOption = $element->find(sprintf($this->option, $count), Locator::SELECTOR_XPATH);
272277
while ($selectOption->isVisible()) {
273-
$listOptions[] = $this->parseOptionText($selectOption->getText());
278+
if ($showSelected) {
279+
$listOptions[] = $this->parseOptionText(
280+
$selectOption->getText(),
281+
$selectOption->getAttribute('selected')
282+
);
283+
} else {
284+
$listOptions[] = $this->parseOptionText($selectOption->getText());
285+
}
274286
++$count;
275287
$selectOption = $element->find(sprintf($this->option, $count), Locator::SELECTOR_XPATH);
276288
}
@@ -279,21 +291,26 @@ protected function getSelectOptionsData(SimpleElement $element, $firstOption = 1
279291
}
280292

281293
/**
282-
* Parse option text to title and price
294+
* Parse option text to title, price and optionally add selected attribute value.
283295
*
284296
* @param string $optionText
297+
* @param string|null $selected
285298
* @return array
286299
*/
287-
protected function parseOptionText($optionText)
300+
protected function parseOptionText($optionText, $selected = null)
288301
{
289302
preg_match('`^(.*?)\+ ?\$(\d.*?)$`sim', $optionText, $match);
290303
$optionPrice = isset($match[2]) ? str_replace(',', '', $match[2]) : 0;
291304
$optionTitle = isset($match[1]) ? trim($match[1]) : $optionText;
292-
293-
return [
305+
$option = [
294306
'title' => $optionTitle,
295307
'price' => $optionPrice
296308
];
309+
if ($selected) {
310+
$option['selected'] = true;
311+
}
312+
313+
return $option;
297314
}
298315

299316
/**
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Bundle\Test\Constraint;
8+
9+
use Magento\Bundle\Test\Fixture\BundleProduct;
10+
use Magento\Checkout\Test\Fixture\Cart;
11+
use Magento\Checkout\Test\Page\CheckoutCart;
12+
use Magento\Checkout\Test\Page\CheckoutCartConfigure;
13+
use Magento\Mtf\Constraint\AbstractAssertForm;
14+
15+
/**
16+
* Assertion that bundle product is correctly displayed on cart configuration page.
17+
*/
18+
class AssertBundleProductOnConfigureCartPage extends AbstractAssertForm
19+
{
20+
/**
21+
* Check bundle product options correctly displayed on cart configuration page.
22+
*
23+
* @param CheckoutCart $checkoutCart
24+
* @param Cart $cart
25+
* @param CheckoutCartConfigure $checkoutCartConfigure
26+
* @return void
27+
*/
28+
public function processAssert(CheckoutCart $checkoutCart, Cart $cart, CheckoutCartConfigure $checkoutCartConfigure)
29+
{
30+
$checkoutCart->open();
31+
$sourceProducts = $cart->getDataFieldConfig('items')['source'];
32+
$products = $sourceProducts->getProducts();
33+
foreach ($cart->getItems() as $key => $item) {
34+
$product = $products[$key];
35+
$cartItem = $checkoutCart->getCartBlock()->getCartItem($product);
36+
$cartItem->edit();
37+
$options = $checkoutCartConfigure->getBundleViewBlock()->getBundleBlock()->getOptions($product, true);
38+
$this->checkOptions($product, $options, $item->getData()['options']);
39+
}
40+
}
41+
42+
/**
43+
* Returns a string representation of the object.
44+
*
45+
* @return string
46+
*/
47+
public function toString()
48+
{
49+
return 'Bundle options data on cart configuration page is correct.';
50+
}
51+
52+
/**
53+
* Compare bundle product options from fixture with product form.
54+
*
55+
* @param BundleProduct $product
56+
* @param array $formOptions
57+
* @param array $cartItemOptions
58+
* @return void
59+
*/
60+
private function checkOptions(BundleProduct $product, array $formOptions, array $cartItemOptions)
61+
{
62+
$productOptions = $this->prepareBundleOptions($product, $cartItemOptions);
63+
$productOptions = $this->sortDataByPath($productOptions, '::title');
64+
foreach ($productOptions as $key => $productOption) {
65+
$productOptions[$key] = $this->sortDataByPath($productOption, 'options::title');
66+
}
67+
$formOptions = $this->sortDataByPath($formOptions, '::title');
68+
foreach ($formOptions as $key => $formOption) {
69+
$formOptions[$key] = $this->sortDataByPath($formOption, 'options::title');
70+
}
71+
72+
$error = $this->verifyData($productOptions, $formOptions);
73+
\PHPUnit_Framework_Assert::assertEmpty($error, $error);
74+
}
75+
76+
/**
77+
* Prepare bundle options.
78+
*
79+
* @param BundleProduct $product
80+
* @param array $cartItemOptions
81+
* @return array
82+
*/
83+
private function prepareBundleOptions(BundleProduct $product, array $cartItemOptions)
84+
{
85+
$bundleSelections = $product->getBundleSelections();
86+
$bundleOptions = isset($bundleSelections['bundle_options']) ? $bundleSelections['bundle_options'] : [];
87+
$result = [];
88+
foreach ($bundleOptions as $optionKey => $bundleOption) {
89+
$optionData = [
90+
'title' => $bundleOption['title'],
91+
'type' => $bundleOption['frontend_type'],
92+
'is_require' => $bundleOption['required'],
93+
];
94+
$key = 0;
95+
foreach ($bundleOption['assigned_products'] as $productKey => $assignedProduct) {
96+
if ($this->isInStock($product, $key++)) {
97+
$price = isset($assignedProduct['data']['selection_price_value'])
98+
? $assignedProduct['data']['selection_price_value']
99+
: $bundleSelections['products'][$optionKey][$productKey]->getPrice();
100+
$title = $assignedProduct['search_data']['name'];
101+
$optionData['options'][$productKey] = [
102+
'title' => $title,
103+
'price' => number_format($price, 2),
104+
];
105+
foreach ($cartItemOptions as $option) {
106+
if (strpos($option['value'], $title)) {
107+
$optionData['options'][$productKey]['selected'] = true;
108+
}
109+
}
110+
}
111+
}
112+
$result[$optionKey] = $optionData;
113+
}
114+
115+
return $result;
116+
}
117+
118+
/**
119+
* Check product is in stock.
120+
*
121+
* @param BundleProduct $product
122+
* @param int $key
123+
* @return bool
124+
*/
125+
private function isInStock(BundleProduct $product, int $key)
126+
{
127+
$assignedProducts = $product->getBundleSelections()['products'][0];
128+
$status = $assignedProducts[$key]->getData()['quantity_and_stock_status']['is_in_stock'];
129+
130+
return $status === 'In Stock';
131+
}
132+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd">
9+
<page name="CheckoutCartConfigure" mca="checkout/cart/configure" module="Magento_Checkout">
10+
<block name="viewBlock">
11+
<render name="bundle" class="Magento\Bundle\Test\Block\Catalog\Product\View" />
12+
</block>
13+
<block name="bundleViewBlock" class="Magento\Bundle\Test\Block\Catalog\Product\View" locator="#maincontent" strategy="css selector" />
14+
</page>
15+
</config>

dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,5 +478,43 @@
478478
<item name="dataset" xsi:type="string">default_with_one_simple_product_and_custom_option</item>
479479
</field>
480480
</dataset>
481+
482+
<dataset name="bundle_with_multiselect_option_one_selection">
483+
<field name="name" xsi:type="string">Bundle with multiselect option %isolation%</field>
484+
<field name="url_key" xsi:type="string">bundle-with-multiselect-option-%isolation%</field>
485+
<field name="sku" xsi:type="string">sku_bundle_with_multiselect_option_%isolation%</field>
486+
<field name="sku_type" xsi:type="string">Yes</field>
487+
<field name="price_type" xsi:type="string">Yes</field>
488+
<field name="website_ids" xsi:type="array">
489+
<item name="0" xsi:type="array">
490+
<item name="dataset" xsi:type="string">default</item>
491+
</item>
492+
</field>
493+
<field name="bundle_selections" xsi:type="array">
494+
<item name="dataset" xsi:type="string">multiselect_option</item>
495+
</field>
496+
<field name="checkout_data" xsi:type="array">
497+
<item name="dataset" xsi:type="string">bundle_multiselect_one_option</item>
498+
</field>
499+
</dataset>
500+
501+
<dataset name="bundle_with_multiselect_option_two_selections">
502+
<field name="name" xsi:type="string">Bundle with multiselect option %isolation%</field>
503+
<field name="url_key" xsi:type="string">bundle-with-multiselect-option-%isolation%</field>
504+
<field name="sku" xsi:type="string">sku_bundle_with_multiselect_option_%isolation%</field>
505+
<field name="sku_type" xsi:type="string">Yes</field>
506+
<field name="price_type" xsi:type="string">Yes</field>
507+
<field name="website_ids" xsi:type="array">
508+
<item name="0" xsi:type="array">
509+
<item name="dataset" xsi:type="string">default</item>
510+
</item>
511+
</field>
512+
<field name="bundle_selections" xsi:type="array">
513+
<item name="dataset" xsi:type="string">multiselect_option</item>
514+
</field>
515+
<field name="checkout_data" xsi:type="array">
516+
<item name="dataset" xsi:type="string">bundle_multiselect_two_options</item>
517+
</field>
518+
</dataset>
481519
</repository>
482520
</config>

dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,5 +1066,44 @@
10661066
</item>
10671067
</field>
10681068
</dataset>
1069+
1070+
<dataset name="multiselect_option">
1071+
<field name="bundle_options" xsi:type="array">
1072+
<item name="0" xsi:type="array">
1073+
<item name="title" xsi:type="string">Multiple Select Option</item>
1074+
<item name="type" xsi:type="string">Multiple Select</item>
1075+
<item name="frontend_type" xsi:type="string">Multiple Select</item>
1076+
<item name="required" xsi:type="string">Yes</item>
1077+
<item name="assigned_products" xsi:type="array">
1078+
<item name="0" xsi:type="array">
1079+
<item name="search_data" xsi:type="array">
1080+
<item name="name" xsi:type="string">%product_name%</item>
1081+
</item>
1082+
<item name="data" xsi:type="array">
1083+
<item name="selection_price_value" xsi:type="string">560.00</item>
1084+
<item name="selection_price_type" xsi:type="string">Fixed</item>
1085+
<item name="selection_qty" xsi:type="string">1</item>
1086+
</item>
1087+
</item>
1088+
<item name="1" xsi:type="array">
1089+
<item name="search_data" xsi:type="array">
1090+
<item name="name" xsi:type="string">%product_name%</item>
1091+
</item>
1092+
<item name="data" xsi:type="array">
1093+
<item name="selection_price_value" xsi:type="string">100.00</item>
1094+
<item name="selection_price_type" xsi:type="string">Fixed</item>
1095+
<item name="selection_qty" xsi:type="string">1</item>
1096+
</item>
1097+
</item>
1098+
</item>
1099+
</item>
1100+
</field>
1101+
<field name="products" xsi:type="array">
1102+
<item name="0" xsi:type="array">
1103+
<item name="0" xsi:type="string">catalogProductSimple::default</item>
1104+
<item name="1" xsi:type="string">catalogProductSimple::product_100_dollar</item>
1105+
</item>
1106+
</field>
1107+
</dataset>
10691108
</repository>
10701109
</config>

0 commit comments

Comments
 (0)