Skip to content

Commit 3146de3

Browse files
committed
Merge remote-tracking branch 'local/ACP2E-1784' into PR_Jun_06_2023
2 parents 4cf0829 + ef4149d commit 3146de3

23 files changed

+754
-25
lines changed

app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
<element name="asLowAsFinalPrice" type="text" selector="div.price-box.price-final_price p.minimal-price > span.price-final_price span.price"/>
1717
<element name="fixedFinalPrice" type="text" selector="div.price-box.price-final_price > span.price-final_price span.price"/>
1818
<element name="productBundleOptionsCheckbox" type="checkbox" selector="//*[@id='product-options-wrapper']//div[@class='fieldset']//label[contains(.,'{{childName}}')]/../input" parameterized="true" timeout="30"/>
19+
<element name="productBundleOneOptionInput" type="input" selector="//*[@id='product-options-wrapper']//div[@class='fieldset']//label[contains(.,'{{childName}}')]/..//input[contains(@class, 'option')]" parameterized="true" timeout="30"/>
20+
<element name="productBundleOptionQty" type="input" selector="//*[@id='product-options-wrapper']//div[@class='fieldset']//label[contains(.,'{{childName}}')]/..//input[contains(@class, 'qty')]" parameterized="true" timeout="30"/>
1921
<element name="includingTaxPrice" type="text" selector=".//*[@class='price-wrapper price-including-tax']/span"/>
2022
<element name="excludingTaxPrice" type="text" selector=".//*[@class='price-wrapper price-excluding-tax']/span"/>
2123
</section>

app/code/Magento/Bundle/view/base/web/js/price-bundle.js

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ define([
1111
'underscore',
1212
'mage/template',
1313
'priceUtils',
14+
'jquery/jquery.parsequery',
1415
'priceBox'
1516
], function ($, _, mageTemplate, utils) {
1617
'use strict';
@@ -40,9 +41,14 @@ define([
4041
*/
4142
_init: function initPriceBundle() {
4243
var form = this.element,
43-
options = $(this.options.productBundleSelector, form);
44+
options = $(this.options.productBundleSelector, form),
45+
qty = $(this.options.qtyFieldSelector, form);
46+
47+
// Override defaults with URL query parameters and/or inputs values
48+
this._overrideDefaults();
4449

4550
options.trigger('change');
51+
qty.trigger('change');
4652
},
4753

4854
/**
@@ -60,6 +66,71 @@ define([
6066
qty.on('change', this._onQtyFieldChanged.bind(this));
6167
},
6268

69+
/**
70+
* Override default options values settings with either URL query parameters or
71+
* initialized inputs values.
72+
* @private
73+
*/
74+
_overrideDefaults: function () {
75+
var hashIndex = window.location.href.indexOf('#');
76+
77+
if (hashIndex !== -1) {
78+
this._parseQueryParams(window.location.href.substr(hashIndex + 1));
79+
}
80+
},
81+
82+
/**
83+
* Parse query parameters from a query string and set options values based on the
84+
* key value pairs of the parameters.
85+
* @param {*} queryString - URL query string containing query parameters.
86+
* @private
87+
*/
88+
_parseQueryParams: function (queryString) {
89+
var queryParams = $.parseQuery({
90+
query: queryString
91+
}),
92+
selectedValues = [],
93+
form = this.element,
94+
options = $(this.options.productBundleSelector, form),
95+
qtys = $(this.options.qtyFieldSelector, form);
96+
97+
$.each(queryParams, $.proxy(function (key, value) {
98+
qtys.each(function (index, qty) {
99+
if (qty.name === key) {
100+
$(qty).val(value);
101+
}
102+
});
103+
options.each(function (index, option) {
104+
let optionType = $(option).prop('type');
105+
106+
if (option.name === key ||
107+
optionType === 'select-multiple'
108+
&& key.indexOf(option.name.substr(0, option.name.length - 2)) !== false
109+
) {
110+
111+
switch (optionType) {
112+
case 'radio':
113+
$(option).val() === value ? $(option).prop('checked', true) : '';
114+
break;
115+
case 'checkbox':
116+
$(option).prop('checked', true);
117+
break;
118+
case 'hidden':
119+
case 'select-one':
120+
$(option).val(value);
121+
break;
122+
case 'select-multiple':
123+
selectedValues.push(value);
124+
break;
125+
}
126+
if (optionType === 'select-multiple' && selectedValues.length) {
127+
$(option).val(selectedValues);
128+
}
129+
}
130+
});
131+
}, this));
132+
},
133+
63134
/**
64135
* Update price box config with bundle option prices
65136
* @private

app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<element name="price" type="text" selector=".product-info-main [data-price-type='finalPrice']"/>
1717
<element name="productPrice" type="text" selector=".price-final_price"/>
1818
<element name="qty" type="input" selector="#qty"/>
19+
<element name="qtyByClassAndQuantity" type="input" selector="//input[contains(@class,'qty') and @value='{{quantity}}']" parameterized="true"/>
1920
<element name="specialPrice" type="text" selector=".special-price"/>
2021
<element name="specialPriceAmount" type="text" selector=".special-price span.price"/>
2122
<element name="updatedPrice" type="text" selector="div.price-box.price-final_price [data-price-type='finalPrice'] .price"/>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
var config = {
7+
map: {
8+
'*': {
9+
groupedProduct: 'Magento_GroupedProduct/js/grouped-product'
10+
}
11+
}
12+
};

app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,27 @@
2424
<thead>
2525
<tr>
2626
<th class="col item" scope="col"><?= $block->escapeHtml(__('Product Name')) ?></th>
27-
<?php if ($_product->isSaleable()) : ?>
27+
<?php if ($_product->isSaleable()): ?>
2828
<th class="col qty" scope="col"><?= $block->escapeHtml(__('Qty')) ?></th>
2929
<?php endif; ?>
3030
</tr>
3131
</thead>
3232

33-
<?php if ($_hasAssociatedProducts) : ?>
33+
<?php if ($_hasAssociatedProducts): ?>
3434
<tbody>
35-
<?php foreach ($_associatedProducts as $_item) : ?>
35+
<?php foreach ($_associatedProducts as $_item): ?>
3636
<tr>
3737
<td data-th="<?= $block->escapeHtml(__('Product Name')) ?>" class="col item">
3838
<strong class="product-item-name"><?= $block->escapeHtml($_item->getName()) ?></strong>
39-
<?php if ($block->getCanShowProductPrice($_product)) : ?>
40-
<?php if ($block->getCanShowProductPrice($_item)) : ?>
39+
<?php if ($block->getCanShowProductPrice($_product)): ?>
40+
<?php if ($block->getCanShowProductPrice($_item)): ?>
4141
<?= /* @noEscape */ $block->getProductPrice($_item) ?>
4242
<?php endif; ?>
4343
<?php endif; ?>
4444
</td>
45-
<?php if ($_product->isSaleable()) : ?>
45+
<?php if ($_product->isSaleable()): ?>
4646
<td data-th="<?= $block->escapeHtml(__('Qty')) ?>" class="col qty">
47-
<?php if ($_item->isSaleable()) : ?>
47+
<?php if ($_item->isSaleable()): ?>
4848
<div class="control qty">
4949
<input type="number"
5050
name="super_group[<?= $block->escapeHtmlAttr($_item->getId()) ?>]"
@@ -55,7 +55,7 @@
5555
data-validate="{'validate-grouped-qty':'#super-product-table'}"
5656
data-errors-message-box="#validation-message-box"/>
5757
</div>
58-
<?php else : ?>
58+
<?php else: ?>
5959
<div class="stock unavailable" title="<?= $block->escapeHtmlAttr(__('Availability')) ?>">
6060
<span><?= $block->escapeHtml(__('Out of stock')) ?></span>
6161
</div>
@@ -68,7 +68,7 @@
6868
&& trim($block->getProductPriceHtml(
6969
$_item,
7070
\Magento\Catalog\Pricing\Price\TierPrice::PRICE_CODE
71-
))) : ?>
71+
))): ?>
7272
<tr class="row-tier-price">
7373
<td colspan="2">
7474
<?= $block->getProductPriceHtml(
@@ -80,11 +80,11 @@
8080
<?php endif; ?>
8181
<?php endforeach; ?>
8282
</tbody>
83-
<?php else : ?>
83+
<?php else: ?>
8484
<tbody>
8585
<tr>
8686
<td class="unavailable"
87-
colspan="<?php if ($_product->isSaleable()) : ?>4<?php else : ?>3<?php endif; ?>">
87+
colspan="<?php if ($_product->isSaleable()): ?>4<?php else: ?>3<?php endif; ?>">
8888
<?= $block->escapeHtml(__('No options of this product are available.')) ?>
8989
</td>
9090
</tr>
@@ -93,3 +93,11 @@
9393
</table>
9494
</div>
9595
<div id="validation-message-box"></div>
96+
<script type="text/x-magento-init">
97+
{
98+
"#product_addtocart_form": {
99+
"groupedProduct": {
100+
}
101+
}
102+
}
103+
</script>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
define([
6+
'jquery',
7+
'underscore',
8+
'jquery-ui-modules/widget',
9+
'jquery/jquery.parsequery'
10+
], function ($) {
11+
'use strict';
12+
13+
$.widget('mage.groupedProduct', {
14+
options: {
15+
qtySelector: 'input.qty',
16+
qtyNameSelector: 'super_group'
17+
},
18+
19+
/**
20+
* Creates widget
21+
* @private
22+
*/
23+
_create: function () {
24+
// Override defaults with URL query parameters and/or inputs values
25+
this._overrideDefaults();
26+
},
27+
28+
/**
29+
* Override default options values settings with either URL query parameters or
30+
* initialized inputs values.
31+
* @private
32+
*/
33+
_overrideDefaults: function () {
34+
var hashIndex = window.location.href.indexOf('#');
35+
36+
if (hashIndex !== -1) {
37+
this._parseQueryParams(window.location.href.substr(hashIndex + 1));
38+
}
39+
},
40+
41+
/**
42+
* Parse query parameters from a query string and set options values based on the
43+
* key value pairs of the parameters.
44+
* @param {*} queryString - URL query string containing query parameters.
45+
* @private
46+
*/
47+
_parseQueryParams: function (queryString) {
48+
var queryParams = $.parseQuery({
49+
query: queryString
50+
}),
51+
form = this.element,
52+
qtyNameSelector = this.options.qtyNameSelector,
53+
qtys = $(this.options.qtySelector, form);
54+
55+
$.each(queryParams, $.proxy(function (key, value) {
56+
qtys.each(function (index, qty) {
57+
var nameSelector = qtyNameSelector.concat('[', key, ']');
58+
59+
if (qty.name === nameSelector) {
60+
$(qty).val(value);
61+
}
62+
});
63+
}, this));
64+
}
65+
});
66+
67+
return $.mage.groupedProduct;
68+
});

app/code/Magento/Wishlist/Controller/Index/Add.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public function execute()
132132
try {
133133
$buyRequest = new \Magento\Framework\DataObject($requestParams);
134134

135-
$result = $wishlist->addNewItem($product, $buyRequest);
135+
$result = $wishlist->addNewItem($product, $buyRequest, true);
136136
if (is_string($result)) {
137137
throw new LocalizedException(__($result));
138138
}

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

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88

99
namespace Magento\Wishlist\Helper;
1010

11+
use Magento\Catalog\Model\Product;
1112
use Magento\Framework\App\ActionInterface;
1213
use Magento\Framework\App\ObjectManager;
14+
use Magento\Framework\DataObject;
1315
use Magento\Framework\Escaper;
16+
use Magento\Framework\Exception\LocalizedException;
17+
use Magento\Framework\Exception\NoSuchEntityException;
1418
use Magento\Wishlist\Controller\WishlistProviderInterface;
19+
use Magento\Wishlist\Model\Item;
1520

1621
/**
1722
* Wishlist Data Helper
@@ -318,14 +323,18 @@ public function getRemoveParams($item, $addReferer = false)
318323
*/
319324
public function getConfigureUrl($item)
320325
{
321-
return $this->_getUrl(
326+
$query = $this->getItemQueryOptions($item);
327+
$url = $this->_getUrl(
322328
'wishlist/index/configure',
323329
[
324330
'id' => $item->getWishlistItemId(),
325331
'product_id' => $item->getProductId(),
326332
'qty' => (int)$item->getQty()
327333
]
328334
);
335+
$url .= (isset($query['fragment']) && count($query['fragment'])) ?
336+
'#' . http_build_query($query['fragment']) : '';
337+
return $url;
329338
}
330339

331340
/**
@@ -638,6 +647,8 @@ public function isDisplayQty()
638647
* @param \Magento\Wishlist\Model\Item|\Magento\Catalog\Model\Product $item
639648
* @param array $additional
640649
* @return string
650+
*
651+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
641652
*/
642653
public function getProductUrl($item, $additional = [])
643654
{
@@ -646,8 +657,31 @@ public function getProductUrl($item, $additional = [])
646657
} else {
647658
$product = $item->getProduct();
648659
}
660+
661+
$query = $this->getItemQueryOptions($item);
662+
if (isset($query['product'])) {
663+
$product = $query['product'];
664+
}
665+
666+
$url = $product->getUrlModel()->getUrl($product, $query['additional'] ?? []);
667+
if (isset($query['fragment']) && count($query['fragment'])) {
668+
$url .= '#' . http_build_query($query['fragment']);
669+
}
670+
671+
return $url;
672+
}
673+
674+
/**
675+
* Generate query params from product options
676+
*
677+
* @param Item|Product $item
678+
* @return array
679+
* @throws NoSuchEntityException
680+
*/
681+
private function getItemQueryOptions(Item|Product $item): array
682+
{
683+
$query = [];
649684
$buyRequest = $item->getBuyRequest();
650-
$fragment = [];
651685
if (is_object($buyRequest)) {
652686
$config = $buyRequest->getSuperProductConfig();
653687
if ($config && !empty($config['product_id'])) {
@@ -656,17 +690,29 @@ public function getProductUrl($item, $additional = [])
656690
false,
657691
$this->_storeManager->getStore()->getStoreId()
658692
);
693+
$query['product'] = $product;
659694
}
660-
$fragment = $buyRequest->getSuperAttribute() ?? [];
695+
$query['fragment'] = $this->getFragmentByProductType($buyRequest);
661696
if ($buyRequest->getQty()) {
662-
$additional['_query']['qty'] = $buyRequest->getQty();
697+
$query['additional']['_query']['qty'] = $buyRequest->getQty();
663698
}
664699
}
665-
$url = $product->getUrlModel()->getUrl($product, $additional);
666-
if ($fragment) {
667-
$url .= '#' . http_build_query($fragment);
668-
}
700+
return $query;
701+
}
669702

670-
return $url;
703+
/**
704+
* Get product url with options and qty for complex products
705+
*
706+
* @param DataObject $buyRequest
707+
* @return array
708+
*/
709+
private function getFragmentByProductType(DataObject $buyRequest): array
710+
{
711+
$fragment = $buyRequest->getSuperAttribute() ?? $buyRequest->getSuperGroup() ?? [];
712+
if ($buyRequest->getBundleOption()) {
713+
$fragment['bundle_option'] = $buyRequest->getBundleOption() ?? [];
714+
$fragment['bundle_option_qty'] = $buyRequest->getBundleOptionQty() ?? [];
715+
}
716+
return $fragment;
671717
}
672718
}

0 commit comments

Comments
 (0)