Skip to content

Commit 540c332

Browse files
committed
Merge remote-tracking branch 'origin/2.4-develop' into PR_13_OCT_2024
2 parents 56211fb + 88660e7 commit 540c332

File tree

13 files changed

+908
-181
lines changed

13 files changed

+908
-181
lines changed

app/code/Magento/Catalog/view/adminhtml/web/js/category-checkbox-tree.js

+83-135
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,6 @@ define([
1010
], function ($) {
1111
'use strict';
1212

13-
/**
14-
* Recursively adds the 'lastNode' property to the nodes in the nested object.
15-
*
16-
* @param {Array} nodes
17-
* @returns {Array}
18-
*/
19-
function addLastNodeProperty(nodes) {
20-
return nodes.map(node => {
21-
return node.children ? {
22-
...node,
23-
children: addLastNodeProperty(node.children)
24-
} : {
25-
...node,
26-
lastNode: true
27-
};
28-
});
29-
}
30-
3113
/**
3214
* Main function that creates the jstree
3315
*
@@ -48,142 +30,93 @@ define([
4830
rootId: config.rootId,
4931
expanded: config.expanded,
5032
categoryId: config.categoryId,
51-
treeJson: addLastNodeProperty(config.treeJson)
33+
treeJson: config.treeJson
5234
},
53-
checkedNodes = [];
35+
initialSelection = [];
5436

5537
/**
5638
* Get the jstree element by its ID
5739
*/
5840
const treeId = $('#' + options.divId);
5941

6042
/**
61-
* Function to check child nodes based on the checkedNodes array
62-
*
63-
* @param {Object} node
43+
* @return {Element}
6444
*/
65-
function getCheckedNodeIds(node) {
66-
if (node.children_d && node.children_d.length > 0) {
67-
const selectChildrenNodes = node.children_d.filter(item => checkedNodes.includes(item));
68-
69-
if (selectChildrenNodes.length > 0) {
70-
treeId.jstree(false).select_node(selectChildrenNodes);
71-
}
72-
}
45+
function getTargetInput() {
46+
return options.jsFormObject.updateElement;
7347
}
7448

7549
/**
76-
* Initialize the jstree with configuration options
77-
*/
78-
treeId.jstree({
79-
core: {
80-
data: options.treeJson,
81-
check_callback: true
82-
},
83-
plugins: ['checkbox'],
84-
checkbox: {
85-
three_state: false
86-
}
87-
});
88-
89-
/**
90-
* Event handler for 'loaded.jstree' event
50+
* Recursively marks nodes which children are not loaded.
51+
*
52+
* @param {Array} nodes
53+
* @returns {Array}
9154
*/
92-
treeId.on('loaded.jstree', function () {
55+
function prepareNodes(nodes) {
56+
return nodes.map(
57+
function (node) {
58+
let obj = {...node, state: {}};
59+
60+
if (Array.isArray(obj.children)) {
61+
if (obj.children.length > 0) {
62+
obj.children = prepareNodes(obj.children);
63+
} else {
64+
obj.children = true;
65+
}
66+
}
9367

94-
/**
95-
* Get each node in the tree
96-
*/
97-
$(treeId.jstree().get_json('#', {
98-
flat: false
99-
})).each(function () {
100-
let node = treeId.jstree().get_node(this.id, false);
68+
if (obj.expanded) {
69+
obj.state.opened = true;
70+
}
10171

102-
if (node.original.expanded) {
103-
treeId.jstree(true).open_node(node);
104-
}
72+
if (initialSelection.includes(obj.id)) {
73+
obj.state.selected = true;
74+
}
10575

106-
if (options.jsFormObject.updateElement.defaultValue) {
107-
checkedNodes = options.jsFormObject.updateElement.defaultValue.split(',');
76+
return obj;
10877
}
109-
});
110-
});
111-
112-
/**
113-
* Event handler for 'load_node.jstree' event
114-
*/
115-
treeId.on('load_node.jstree', function (e, data) {
116-
getCheckedNodeIds(data.node);
117-
});
118-
119-
/**
120-
* Add lastNode property to child who doesn't have children property
121-
*
122-
* @param {Object} treeData
123-
*/
124-
function addLastNodeFlag(treeData) {
125-
if (treeData.children) {
126-
treeData.children.forEach((child) => addLastNodeFlag(child));
127-
} else {
128-
treeData.lastNode = true;
129-
}
78+
);
13079
}
13180

13281
/**
133-
* Function to handle the 'success' callback of the AJAX request
82+
* Load the node and execute the callback function
13483
*
135-
* @param {Array} response
136-
* @param {Object} childNode
137-
* @param {Object} data
84+
* @param {Object} node
85+
* @param {Function} callback
13886
*/
139-
function handleSuccessResponse(response, childNode, data) {
140-
if (response.length > 0) {
141-
response.forEach(function (newNode) {
142-
addLastNodeFlag(newNode);
143-
144-
/**
145-
* Create the new node and execute node callback
146-
*/
147-
data.instance.create_node(childNode, newNode, 'last', function (node) {
148-
if (checkedNodes.includes(node.id)) {
149-
treeId.jstree(false).select_node(node.id);
150-
}
151-
getCheckedNodeIds(node);
152-
});
87+
function load(node, callback) {
88+
let target = getTargetInput(),
89+
instance = this;
90+
91+
if (node.id === $.jstree.root) {
92+
callback.call(instance, prepareNodes(options.treeJson));
93+
} else if (Array.isArray(node.children) && node.children.length === 0) {
94+
$.ajax({
95+
url: options.dataUrl,
96+
data: {
97+
id: node.id,
98+
selected: target.value
99+
},
100+
dataType: 'json',
101+
success: function (response) {
102+
callback.call(instance, prepareNodes(response));
103+
},
104+
error: function (jqXHR, status, error) {
105+
console.log(status + ': ' + error + '\nResponse text:\n' + jqXHR.responseText);
106+
}
153107
});
108+
} else {
109+
callback.call(instance, false);
154110
}
155111
}
156112

157113
/**
158-
* Event handler for 'open_node.jstree' event
114+
* Event handler for 'init.jstree' event
159115
*/
160-
treeId.on('open_node.jstree', function (e, data) {
161-
let parentNode = data.node;
162-
163-
if (parentNode.children.length > 0) {
164-
let childNode = data.instance.get_node(parentNode.children, false);
165-
166-
/**
167-
* Check if the child node has no children (is not yet loaded)
168-
*/
169-
if (childNode.children && childNode.children.length === 0
170-
&& childNode.original && !childNode.original.lastNode) {
171-
$.ajax({
172-
url: options.dataUrl,
173-
data: {
174-
id: childNode.id,
175-
selected: options.jsFormObject.updateElement.value
176-
},
177-
dataType: 'json',
178-
success: function (response) {
179-
handleSuccessResponse(response, childNode, data);
180-
},
181-
error: function (jqXHR, status, error) {
182-
console.log(status + ': ' + error + '\nResponse text:\n' + jqXHR.responseText);
183-
}
184-
});
185-
}
186-
}
116+
treeId.on('init.jstree', function () {
117+
let target = getTargetInput();
118+
119+
initialSelection = target.value ? target.value.split(',').map(id => id.trim()) : [];
187120
});
188121

189122
/**
@@ -193,19 +126,34 @@ define([
193126
if (data.action === 'ready') {
194127
return;
195128
}
196-
const clickedNodeID = data.node.id, currentCheckedNodes = data.instance.get_checked();
197-
198-
if (data.action === 'select_node' && !checkedNodes.includes(clickedNodeID)) {
199-
checkedNodes = currentCheckedNodes;
200-
} else if (data.action === 'deselect_node') {
201-
checkedNodes = currentCheckedNodes.filter((nodeID) => nodeID !== clickedNodeID);
202-
}
203-
checkedNodes.sort((a, b) => a - b);
204129

205130
/**
206131
* Update the value of the corresponding form element with the checked node IDs
132+
*
133+
* keep the checked nodes that are not in the tree yet,
134+
* and merge them with the currently checked nodes
135+
* then sort the resulted array
207136
*/
208-
options.jsFormObject.updateElement.value = checkedNodes.join(', ');
137+
let target = getTargetInput(),
138+
selected = initialSelection
139+
.filter(node => data.instance.get_node(node) === false)
140+
.concat(data.instance.get_checked());
141+
142+
target.value = [...new Set(selected)].sort((a, b) => a - b).join(',');
143+
});
144+
145+
/**
146+
* Initialize the jstree with configuration options
147+
*/
148+
treeId.jstree({
149+
core: {
150+
data: load,
151+
check_callback: true
152+
},
153+
plugins: ['checkbox'],
154+
checkbox: {
155+
three_state: false
156+
}
209157
});
210158
};
211159
});

app/code/Magento/Quote/Model/Quote/Item/Compare.php

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\Quote\Model\Quote\Item;
77

@@ -68,14 +68,9 @@ protected function getOptionValues($value)
6868
*/
6969
public function compare(Item $target, Item $compared)
7070
{
71-
if ($target->getSku() !== null && $target->getSku() === $compared->getSku()) {
72-
return true;
73-
}
74-
7571
if ($target->getProductId() != $compared->getProductId()) {
7672
return false;
7773
}
78-
7974
$targetOptionByCode = $target->getOptionsByCode();
8075
$comparedOptionsByCode = $compared->getOptionsByCode();
8176
if (!$target->compareOptions($targetOptionByCode, $comparedOptionsByCode)) {

app/code/Magento/Quote/Test/Unit/Model/Quote/Item/CompareTest.php

+2-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -236,19 +236,4 @@ public function testCompareItemWithoutOptionWithCompared()
236236
->willReturn([]);
237237
$this->assertFalse($this->helper->compare($this->itemMock, $this->comparedMock));
238238
}
239-
240-
/**
241-
* test compare two items- when configurable products has assigned sku of its selected variant
242-
*/
243-
public function testCompareConfigurableProductAndItsVariant()
244-
{
245-
$this->itemMock->expects($this->exactly(2))
246-
->method('getSku')
247-
->willReturn('cr1-r');
248-
$this->comparedMock->expects($this->once())
249-
->method('getSku')
250-
->willReturn('cr1-r');
251-
252-
$this->assertTrue($this->helper->compare($this->itemMock, $this->comparedMock));
253-
}
254239
}

app/code/Magento/Reports/Controller/Adminhtml/Report/Product/ExportSoldCsv.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
<?php
22
/**
3-
*
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
65
*/
76
declare(strict_types=1);
87

98
namespace Magento\Reports\Controller\Adminhtml\Report\Product;
109

1110
use Magento\Backend\Block\Widget\Grid\ExportInterface;
12-
use Magento\Framework\App\Action\HttpPostActionInterface;
11+
use Magento\Framework\App\Action\HttpGetActionInterface;
1312
use Magento\Framework\App\ResponseInterface;
1413
use Magento\Framework\App\Filesystem\DirectoryList;
1514
use Magento\Reports\Controller\Adminhtml\Report\Product;
1615

17-
class ExportSoldCsv extends Product implements HttpPostActionInterface
16+
class ExportSoldCsv extends Product implements HttpGetActionInterface
1817
{
1918
/**
2019
* Authorization level of a basic admin session

app/code/Magento/Reports/Controller/Adminhtml/Report/Product/ExportSoldExcel.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
<?php
22
/**
3-
*
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
65
*/
76
declare(strict_types=1);
87

98
namespace Magento\Reports\Controller\Adminhtml\Report\Product;
109

1110
use Magento\Backend\Block\Widget\Grid\ExportInterface;
12-
use Magento\Framework\App\Action\HttpPostActionInterface;
11+
use Magento\Framework\App\Action\HttpGetActionInterface;
1312
use Magento\Framework\App\ResponseInterface;
1413
use Magento\Framework\App\Filesystem\DirectoryList;
1514
use Magento\Reports\Controller\Adminhtml\Report\Product;
1615

17-
class ExportSoldExcel extends Product implements HttpPostActionInterface
16+
class ExportSoldExcel extends Product implements HttpGetActionInterface
1817
{
1918
/**
2019
* Authorization level of a basic admin session
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Reports\Test\Integration\Controller\Adminhtml\Report\Product;
9+
10+
use Magento\TestFramework\TestCase\AbstractBackendController;
11+
12+
/**
13+
* @magentoAppArea adminhtml
14+
*/
15+
class ExportSoldCsvTest extends AbstractBackendController
16+
{
17+
public function testExecute() : void
18+
{
19+
$this->dispatch('backend/reports/report_product/exportSoldCsv');
20+
$this->assertEquals(302, $this->getResponse()->getHttpResponseCode());
21+
}
22+
}

0 commit comments

Comments
 (0)