Skip to content

Commit f905c6d

Browse files
committed
Merge branch '2.4.7-beta3-develop' into AC-9028
2 parents e4641ed + 31a9c8d commit f905c6d

File tree

720 files changed

+50866
-64348
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

720 files changed

+50866
-64348
lines changed

app/code/Magento/Backend/Test/Unit/Model/Menu/Config/_files/invalidMenuXmlArray.php

+314-128
Large diffs are not rendered by default.

app/code/Magento/Backend/view/adminhtml/web/js/dashboard/chart.js

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ define([
1717
$.widget('mage.dashboardChart', {
1818
options: {
1919
updateUrl: '',
20+
responsive: true,
21+
maintainAspectRatio: false,
2022
periodSelect: null,
2123
periodUnits: [],
2224
precision: 0,

app/code/Magento/Backup/Model/Fs/Collection.php

+20-6
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ class Collection extends \Magento\Framework\Data\Collection\Filesystem
2929
protected $_path = 'backups';
3030

3131
/**
32-
* Backup data
33-
*
3432
* @var \Magento\Backup\Helper\Data
3533
*/
3634
protected $_backupData = null;
@@ -46,7 +44,9 @@ class Collection extends \Magento\Framework\Data\Collection\Filesystem
4644
* @var \Magento\Framework\Filesystem
4745
*/
4846
private $_filesystem;
47+
4948
/**
49+
*
5050
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
5151
* @param \Magento\Backup\Helper\Data $backupData
5252
* @param \Magento\Framework\Filesystem $filesystem
@@ -61,21 +61,26 @@ public function __construct(
6161
) {
6262
$this->_backupData = $backupData;
6363
parent::__construct($entityFactory, $filesystem);
64-
6564
$this->_filesystem = $filesystem;
6665
$this->_backup = $backup;
6766
$this->_varDirectory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
68-
6967
$this->_hideBackupsForApache();
68+
$this->initialize();
69+
}
7070

71+
/**
72+
* Initialize collection
73+
*
74+
* @return void
75+
*/
76+
private function initialize()
77+
{
7178
// set collection specific params
7279
$extensions = $this->_backupData->getExtensions();
73-
7480
foreach ($extensions as $value) {
7581
$extensions[] = '(' . preg_quote($value, '/') . ')';
7682
}
7783
$extensions = implode('|', $extensions);
78-
7984
$this->_varDirectory->create($this->_path);
8085
$path = rtrim($this->_varDirectory->getAbsolutePath($this->_path), '/') . '/';
8186
$this->setOrder(
@@ -90,6 +95,15 @@ public function __construct(
9095
);
9196
}
9297

98+
/**
99+
* @inheritDoc
100+
*/
101+
public function _resetState(): void
102+
{
103+
parent::_resetState();
104+
$this->initialize();
105+
}
106+
93107
/**
94108
* Create .htaccess file and deny backups directory access from web
95109
*

app/code/Magento/Bundle/Pricing/Adjustment/DefaultSelectionPriceListProvider.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,6 @@ private function getBundleOptions(Product $saleableItem)
255255
*/
256256
public function _resetState(): void
257257
{
258-
$this->priceList = [];
258+
$this->priceList = null;
259259
}
260260
}

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

+2
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

+72-1
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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\BundleGraphQl\Model\Resolver;
9+
10+
use Magento\Catalog\Model\Product;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\GraphQl\Config\Element\Field;
13+
use Magento\Framework\GraphQl\Query\ResolverInterface;
14+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
15+
16+
class BundlePriceDetails implements ResolverInterface
17+
{
18+
/**
19+
* @inheritdoc
20+
*/
21+
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
22+
{
23+
if (!isset($value['model'])) {
24+
throw new LocalizedException(__('"model" value should be specified'));
25+
}
26+
/** @var Product $product */
27+
$product = $value['model'];
28+
29+
$price = $product->getPrice();
30+
$finalPrice = $product->getFinalPrice();
31+
$discountPercentage = 100 - (($finalPrice * 100) / $price);
32+
return [
33+
'main_price' => $price,
34+
'main_final_price' => $finalPrice,
35+
'discount_percentage' => $discountPercentage
36+
];
37+
}
38+
}

app/code/Magento/BundleGraphQl/etc/schema.graphqls

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ type SelectedBundleOptionValue @doc(description: "Contains details about a value
4747
price: Float! @doc(description: "The price of the value for the selected bundle product option.")
4848
}
4949

50+
type PriceDetails @doc(description: "Can be used to retrieve the main price details in case of bundle product") {
51+
main_price: Float @doc(description: "The regular price of the main product")
52+
main_final_price: Float @doc(description: "The final price after applying the discount to the main product")
53+
discount_percentage: Float @doc(description: "The percentage of discount applied to the main product price")
54+
}
55+
5056
type BundleItem @doc(description: "Defines an individual item within a bundle product.") {
5157
option_id: Int @deprecated(reason: "Use `uid` instead") @doc(description: "An ID assigned to each type of item in a bundle product.")
5258
uid: ID @doc(description: "The unique ID for a `BundleItem` object.")
@@ -79,6 +85,7 @@ type BundleProduct implements ProductInterface, RoutableInterface, PhysicalProdu
7985
dynamic_sku: Boolean @doc(description: "Indicates whether the bundle product has a dynamic SKU.") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Product\\Fields\\DynamicSku")
8086
ship_bundle_items: ShipBundleItemsEnum @doc(description: "Indicates whether to ship bundle items together or individually.") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Product\\Fields\\ShipBundleItems")
8187
dynamic_weight: Boolean @doc(description: "Indicates whether the bundle product has a dynamically calculated weight.") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Product\\Fields\\DynamicWeight")
88+
price_details: PriceDetails @doc(description: "The price details of the main product") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\BundlePriceDetails")
8289
items: [BundleItem] @doc(description: "An array containing information about individual bundle items.") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\BundleItems")
8390
}
8491

app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php

+21-16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\BundleImportExport\Model\Import\Product\Type;
89

@@ -181,22 +182,26 @@ protected function parseSelections($rowData, $entityId)
181182
return [];
182183
}
183184

184-
$rowData['bundle_values'] = str_replace(
185-
self::BEFORE_OPTION_VALUE_DELIMITER,
186-
$this->_entityModel->getMultipleValueSeparator(),
187-
$rowData['bundle_values']
188-
);
189-
$selections = explode(
190-
Product::PSEUDO_MULTI_LINE_SEPARATOR,
191-
$rowData['bundle_values']
192-
);
185+
if (is_string($rowData['bundle_values'])) {
186+
$rowData['bundle_values'] = str_replace(
187+
self::BEFORE_OPTION_VALUE_DELIMITER,
188+
$this->_entityModel->getMultipleValueSeparator(),
189+
$rowData['bundle_values']
190+
);
191+
$selections = explode(
192+
Product::PSEUDO_MULTI_LINE_SEPARATOR,
193+
$rowData['bundle_values']
194+
);
195+
} else {
196+
$selections = $rowData['bundle_values'];
197+
}
198+
193199
foreach ($selections as $selection) {
194-
$values = explode($this->_entityModel->getMultipleValueSeparator(), $selection);
195-
$option = $this->parseOption($values);
196-
if (isset($option['sku']) && isset($option['name'])) {
197-
if (!isset($this->_cachedOptions[$entityId])) {
198-
$this->_cachedOptions[$entityId] = [];
199-
}
200+
$option = is_string($selection)
201+
? $this->parseOption(explode($this->_entityModel->getMultipleValueSeparator(), $selection))
202+
: $selection;
203+
204+
if (isset($option['sku'], $option['name'])) {
200205
$this->_cachedSkus[] = $option['sku'];
201206
if (!isset($this->_cachedOptions[$entityId][$option['name']])) {
202207
$this->_cachedOptions[$entityId][$option['name']] = [];
@@ -779,7 +784,7 @@ private function getStoreIdByCode(string $storeCode): int
779784
if (!isset($this->storeCodeToId[$storeCode])) {
780785
/** @var $store Store */
781786
foreach ($this->storeManager->getStores() as $store) {
782-
$this->storeCodeToId[$store->getCode()] = $store->getId();
787+
$this->storeCodeToId[$store->getCode()] = (int)$store->getId();
783788
}
784789
}
785790

app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php

+13-12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*/
1414
namespace Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Gallery;
1515

16+
use Magento\Catalog\Helper\Image;
1617
use Magento\Framework\App\ObjectManager;
1718
use Magento\Backend\Block\Media\Uploader;
1819
use Magento\Framework\Json\Helper\Data as JsonHelper;
@@ -45,7 +46,7 @@ class Content extends \Magento\Backend\Block\Widget
4546
protected $_jsonEncoder;
4647

4748
/**
48-
* @var \Magento\Catalog\Helper\Image
49+
* @var Image
4950
*/
5051
private $imageHelper;
5152

@@ -67,6 +68,7 @@ class Content extends \Magento\Backend\Block\Widget
6768
* @param ImageUploadConfigDataProvider $imageUploadConfigDataProvider
6869
* @param Database $fileStorageDatabase
6970
* @param JsonHelper|null $jsonHelper
71+
* @param Image|null $imageHelper
7072
*/
7173
public function __construct(
7274
\Magento\Backend\Block\Template\Context $context,
@@ -75,7 +77,8 @@ public function __construct(
7577
array $data = [],
7678
ImageUploadConfigDataProvider $imageUploadConfigDataProvider = null,
7779
Database $fileStorageDatabase = null,
78-
?JsonHelper $jsonHelper = null
80+
?JsonHelper $jsonHelper = null,
81+
?Image $imageHelper = null
7982
) {
8083
$this->_jsonEncoder = $jsonEncoder;
8184
$this->_mediaConfig = $mediaConfig;
@@ -85,6 +88,7 @@ public function __construct(
8588
?: ObjectManager::getInstance()->get(ImageUploadConfigDataProvider::class);
8689
$this->fileStorageDatabase = $fileStorageDatabase
8790
?: ObjectManager::getInstance()->get(Database::class);
91+
$this->imageHelper = $imageHelper ?: ObjectManager::getInstance()->get(Image::class);
8892
}
8993

9094
/**
@@ -191,7 +195,7 @@ public function getImagesJson()
191195
$fileHandler = $mediaDir->stat($this->_mediaConfig->getMediaPath($image['file']));
192196
$image['size'] = $fileHandler['size'];
193197
} catch (FileSystemException $e) {
194-
$image['url'] = $this->getImageHelper()->getDefaultPlaceholderUrl('small_image');
198+
$image['url'] = $this->imageHelper->getDefaultPlaceholderUrl('small_image');
195199
$image['size'] = 0;
196200
$this->_logger->warning($e);
197201
}
@@ -304,17 +308,14 @@ public function getImageTypesJson()
304308
}
305309

306310
/**
307-
* Returns image helper object.
311+
* Flag if gallery content editing is enabled.
308312
*
309-
* @return \Magento\Catalog\Helper\Image
310-
* @deprecated 101.0.3
313+
* Is enabled by default, exposed to interceptors to add custom logic
314+
*
315+
* @return bool
311316
*/
312-
private function getImageHelper()
317+
public function isEditEnabled() : bool
313318
{
314-
if ($this->imageHelper === null) {
315-
$this->imageHelper = \Magento\Framework\App\ObjectManager::getInstance()
316-
->get(\Magento\Catalog\Helper\Image::class);
317-
}
318-
return $this->imageHelper;
319+
return true;
319320
}
320321
}

0 commit comments

Comments
 (0)