Skip to content

Commit 3a4f503

Browse files
committed
Merge branch '2.4-develop' of https://github.com/magento-l3/magento2ce into MC-42249
2 parents 3410ca3 + bf4cdad commit 3a4f503

File tree

9 files changed

+322
-74
lines changed

9 files changed

+322
-74
lines changed

app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Indexer/ProductRuleReindex.php

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66
*/
77
namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Indexer;
88

9+
use Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer;
910
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
1011
use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider;
1112

1213
/**
13-
* Class ReindexProduct. Add configurable sub-products to reindex
14+
* Add configurable sub-products to reindex
1415
*/
1516
class ProductRuleReindex
1617
{
1718
/**
18-
* @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable
19+
* @var Configurable
1920
*/
2021
private $configurable;
2122

2223
/**
23-
* @var \Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider
24+
* @var ConfigurableProductsProvider
2425
*/
2526
private $configurableProductsProvider;
2627

@@ -37,61 +38,47 @@ public function __construct(
3738
}
3839

3940
/**
40-
* @param \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
41+
* Reindex configurable product with sub-products
42+
*
43+
* @param ProductRuleIndexer $subject
4144
* @param \Closure $proceed
4245
* @param int $id
43-
*
4446
* @return void
4547
*/
46-
public function aroundExecuteRow(
47-
\Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject,
48-
\Closure $proceed,
49-
$id
50-
) {
48+
public function aroundExecuteRow(ProductRuleIndexer $subject, \Closure $proceed, $id)
49+
{
50+
$isReindexed = false;
51+
5152
$configurableProductIds = $this->configurableProductsProvider->getIds([$id]);
52-
$this->reindexSubProducts($configurableProductIds, $subject);
53-
if (!$configurableProductIds) {
54-
$proceed($id);
53+
if ($configurableProductIds) {
54+
$subProducts = array_values($this->configurable->getChildrenIds($id)[0]);
55+
if ($subProducts) {
56+
$subject->executeList(array_merge([$id], $subProducts));
57+
$isReindexed = true;
58+
}
5559
}
56-
}
5760

58-
/**
59-
* @param \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
60-
* @param \Closure $proceed
61-
* @param array $ids
62-
*
63-
* @return void
64-
*/
65-
public function aroundExecuteList(
66-
\Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject,
67-
\Closure $proceed,
68-
array $ids
69-
) {
70-
$configurableProductIds = $this->configurableProductsProvider->getIds($ids);
71-
$subProducts = $this->reindexSubProducts($configurableProductIds, $subject);
72-
$ids = array_diff($ids, $configurableProductIds, $subProducts);
73-
if ($ids) {
74-
$proceed($ids);
61+
if (!$isReindexed) {
62+
$proceed($id);
7563
}
7664
}
7765

7866
/**
79-
* @param array $configurableIds
80-
* @param \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
67+
* Add sub-products to reindex
8168
*
69+
* @param ProductRuleIndexer $subject
70+
* @param array $ids
8271
* @return array
72+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
8373
*/
84-
private function reindexSubProducts(
85-
array $configurableIds,
86-
\Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
87-
) {
88-
$subProducts = [];
89-
if ($configurableIds) {
90-
$subProducts = array_values($this->configurable->getChildrenIds($configurableIds)[0]);
91-
if ($subProducts) {
92-
$subject->executeList($subProducts);
93-
}
74+
public function beforeExecuteList(ProductRuleIndexer $subject, array $ids): array
75+
{
76+
$configurableProductIds = $this->configurableProductsProvider->getIds($ids);
77+
if ($configurableProductIds) {
78+
$subProducts = array_values($this->configurable->getChildrenIds($configurableProductIds)[0]);
79+
$ids = array_unique(array_merge($ids, $subProducts));
9480
}
95-
return $subProducts;
81+
82+
return [$ids];
9683
}
9784
}

app/code/Magento/Paypal/Controller/Payflow/ReturnUrl.php

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
*/
1919
class ReturnUrl extends Payflow implements CsrfAwareActionInterface, HttpGetActionInterface
2020
{
21+
private const ORDER_INCREMENT_ID = 'INVNUM';
22+
23+
private const SILENT_POST_HASH = 'secure_silent_post_hash';
24+
2125
/**
2226
* @var array of allowed order states on frontend
2327
*/
@@ -63,30 +67,48 @@ public function execute()
6367
$this->_view->loadLayout(false);
6468
/** @var \Magento\Checkout\Block\Onepage\Success $redirectBlock */
6569
$redirectBlock = $this->_view->getLayout()->getBlock($this->_redirectBlockName);
66-
67-
if ($this->_checkoutSession->getLastRealOrderId()) {
68-
/** @var \Magento\Sales\Model\Order $order */
69-
$order = $this->_orderFactory->create()->loadByIncrementId($this->_checkoutSession->getLastRealOrderId());
70-
71-
if ($order->getIncrementId()) {
72-
if ($this->checkOrderState($order)) {
73-
$redirectBlock->setData('goto_success_page', true);
70+
$order = $this->getOrderFromRequest();
71+
if ($order) {
72+
if ($this->checkOrderState($order)) {
73+
$redirectBlock->setData('goto_success_page', true);
74+
} else {
75+
if ($this->checkPaymentMethod($order)) {
76+
$gotoSection = $this->_cancelPayment((string)$this->getRequest()->getParam('RESPMSG'));
77+
$redirectBlock->setData('goto_section', $gotoSection);
78+
$redirectBlock->setData('error_msg', __('Your payment has been declined. Please try again.'));
7479
} else {
75-
if ($this->checkPaymentMethod($order)) {
76-
$gotoSection = $this->_cancelPayment((string)$this->getRequest()->getParam('RESPMSG'));
77-
$redirectBlock->setData('goto_section', $gotoSection);
78-
$redirectBlock->setData('error_msg', __('Your payment has been declined. Please try again.'));
79-
} else {
80-
$redirectBlock->setData('goto_section', false);
81-
$redirectBlock->setData('error_msg', __('Requested payment method does not match with order.'));
82-
}
80+
$redirectBlock->setData('goto_section', false);
81+
$redirectBlock->setData('error_msg', __('Requested payment method does not match with order.'));
8382
}
8483
}
8584
}
8685

8786
$this->_view->renderLayout();
8887
}
8988

89+
/**
90+
* Returns an order from request.
91+
*
92+
* @return Order|null
93+
*/
94+
private function getOrderFromRequest(): ?Order
95+
{
96+
$orderId = $this->getRequest()->getParam(self::ORDER_INCREMENT_ID);
97+
if (!$orderId) {
98+
return null;
99+
}
100+
101+
$order = $this->_orderFactory->create()->loadByIncrementId($orderId);
102+
$storedHash = (string)$order->getPayment()->getAdditionalInformation(self::SILENT_POST_HASH);
103+
$requestHash = (string)$this->getRequest()->getParam('USER2');
104+
if (empty($storedHash) || empty($requestHash) || !hash_equals($storedHash, $requestHash)) {
105+
return null;
106+
}
107+
$this->_checkoutSession->setLastRealOrderId($orderId);
108+
109+
return $order;
110+
}
111+
90112
/**
91113
* Check order state
92114
*

app/code/Magento/Paypal/Plugin/TransparentSessionChecker.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class TransparentSessionChecker
2020
*/
2121
private $disableSessionUrls = [
2222
'paypal/transparent/redirect',
23+
'paypal/payflowadvanced/returnUrl',
24+
'paypal/payflow/returnUrl',
2325
'paypal/hostedpro/return',
2426
];
2527

app/code/Magento/Paypal/Test/Unit/Controller/Payflow/ReturnUrlTest.php

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class ReturnUrlTest extends TestCase
3232
{
3333
const LAST_REAL_ORDER_ID = '000000001';
3434

35+
const SILENT_POST_HASH = 'abcdfg';
36+
3537
/**
3638
* @var ReturnUrl
3739
*/
@@ -142,7 +144,7 @@ protected function setUp(): void
142144

143145
$this->checkoutSession = $this->getMockBuilder(Session::class)
144146
->disableOriginalConstructor()
145-
->setMethods(['getLastRealOrderId', 'getLastRealOrder', 'restoreQuote'])
147+
->setMethods(['setLastRealOrderId', 'getLastRealOrder', 'restoreQuote'])
146148
->getMock();
147149

148150
$this->paymentFailures = $this->getMockBuilder(PaymentFailuresInterface::class)
@@ -177,8 +179,15 @@ public function testExecuteAllowedOrderState($state)
177179
$this->withLayout();
178180
$this->withOrder(self::LAST_REAL_ORDER_ID, $state);
179181

180-
$this->checkoutSession->method('getLastRealOrderId')
181-
->willReturn(self::LAST_REAL_ORDER_ID);
182+
$this->request->method('getParam')
183+
->willReturnMap([
184+
['INVNUM', self::LAST_REAL_ORDER_ID],
185+
['USER2', self::SILENT_POST_HASH],
186+
]);
187+
188+
$this->checkoutSession->expects($this->once())
189+
->method('setLastRealOrderId')
190+
->with(self::LAST_REAL_ORDER_ID);
182191

183192
$this->block->method('setData')
184193
->with('goto_success_page', true)
@@ -202,6 +211,45 @@ public function allowedOrderStateDataProvider()
202211
];
203212
}
204213

214+
/**
215+
* Checks a test case when silent post hash validation fails.
216+
*
217+
* @param string $requestHash
218+
* @param string $orderHash
219+
* @dataProvider invalidHashVariations
220+
*/
221+
public function testFailedHashValidation(string $requestHash, string $orderHash)
222+
{
223+
$this->withLayout();
224+
$this->withOrder(self::LAST_REAL_ORDER_ID, Order::STATE_PROCESSING, $orderHash);
225+
226+
$this->request->method('getParam')
227+
->willReturnMap([
228+
['INVNUM', self::LAST_REAL_ORDER_ID],
229+
['USER2', $requestHash],
230+
]);
231+
232+
$this->checkoutSession->expects($this->never())
233+
->method('setLastRealOrderId')
234+
->with(self::LAST_REAL_ORDER_ID);
235+
236+
$this->returnUrl->execute();
237+
}
238+
239+
/**
240+
* Gets list of allowed order states.
241+
*
242+
* @return array
243+
*/
244+
public function invalidHashVariations()
245+
{
246+
return [
247+
['requestHash' => '', 'orderHash' => self::SILENT_POST_HASH],
248+
['requestHash' => self::SILENT_POST_HASH, 'orderHash' => ''],
249+
['requestHash' => 'abcd', 'orderHash' => 'dcba'],
250+
];
251+
}
252+
205253
/**
206254
* Checks a test case when action processes order with not allowed state.
207255
*
@@ -218,8 +266,11 @@ public function testExecuteNotAllowedOrderState($state, $restoreQuote, $expected
218266
$this->withCheckoutSession(self::LAST_REAL_ORDER_ID, $restoreQuote);
219267

220268
$this->request->method('getParam')
221-
->with('RESPMSG')
222-
->willReturn($errMessage);
269+
->willReturnMap([
270+
['RESPMSG', $errMessage],
271+
['INVNUM', self::LAST_REAL_ORDER_ID],
272+
['USER2', self::SILENT_POST_HASH],
273+
]);
223274

224275
$this->payment->method('getMethod')
225276
->willReturn(Config::METHOD_PAYFLOWLINK);
@@ -261,8 +312,14 @@ public function testCheckRejectByPaymentMethod()
261312
$this->withLayout();
262313
$this->withOrder(self::LAST_REAL_ORDER_ID, Order::STATE_NEW);
263314

264-
$this->checkoutSession->method('getLastRealOrderId')
265-
->willReturn(self::LAST_REAL_ORDER_ID);
315+
$this->checkoutSession->expects($this->once())
316+
->method('setLastRealOrderId')
317+
->with(self::LAST_REAL_ORDER_ID);
318+
$this->request->method('getParam')
319+
->willReturnMap([
320+
['INVNUM', self::LAST_REAL_ORDER_ID],
321+
['USER2', self::SILENT_POST_HASH],
322+
]);
266323

267324
$this->withBlockContent(false, 'Requested payment method does not match with order.');
268325

@@ -285,8 +342,11 @@ public function testCheckXSSEscaped($errorMsg, $errorMsgEscaped)
285342
$this->withCheckoutSession(self::LAST_REAL_ORDER_ID, true);
286343

287344
$this->request->method('getParam')
288-
->with('RESPMSG')
289-
->willReturn($errorMsg);
345+
->willReturnMap([
346+
['RESPMSG', $errorMsg],
347+
['INVNUM', self::LAST_REAL_ORDER_ID],
348+
['USER2', self::SILENT_POST_HASH],
349+
]);
290350

291351
$this->checkoutHelper->method('cancelCurrentOrder')
292352
->with(self::equalTo($errorMsgEscaped));
@@ -323,8 +383,11 @@ public function testCheckAdvancedAcceptingByPaymentMethod()
323383
$this->withCheckoutSession(self::LAST_REAL_ORDER_ID, true);
324384

325385
$this->request->method('getParam')
326-
->with('RESPMSG')
327-
->willReturn('message');
386+
->willReturnMap([
387+
['RESPMSG', 'message'],
388+
['INVNUM', self::LAST_REAL_ORDER_ID],
389+
['USER2', self::SILENT_POST_HASH],
390+
]);
328391

329392
$this->withBlockContent('paymentMethod', 'Your payment has been declined. Please try again.');
330393

@@ -347,9 +410,10 @@ public function testCheckAdvancedAcceptingByPaymentMethod()
347410
*
348411
* @param string $incrementId
349412
* @param string $state
413+
* @param string $hash
350414
* @return void
351415
*/
352-
private function withOrder($incrementId, $state)
416+
private function withOrder($incrementId, $state, $hash = self::SILENT_POST_HASH)
353417
{
354418
$this->orderFactory->method('create')
355419
->willReturn($this->order);
@@ -366,6 +430,8 @@ private function withOrder($incrementId, $state)
366430

367431
$this->order->method('getPayment')
368432
->willReturn($this->payment);
433+
$this->payment->method('getAdditionalInformation')
434+
->willReturn($hash);
369435
}
370436

371437
/**
@@ -390,8 +456,8 @@ private function withLayout()
390456
*/
391457
private function withCheckoutSession($orderId, $restoreQuote)
392458
{
393-
$this->checkoutSession->method('getLastRealOrderId')
394-
->willReturn($orderId);
459+
$this->checkoutSession->method('setLastRealOrderId')
460+
->with($orderId);
395461

396462
$this->checkoutSession->method('getLastRealOrder')
397463
->willReturn($this->order);

app/code/Magento/Paypal/etc/csp_whitelist.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@
3636
<values>
3737
<value id="www_paypal" type="host">www.paypal.com</value>
3838
<value id="www_sandbox_paypal" type="host">www.sandbox.paypal.com</value>
39+
<value id="pilot_payflowlink_paypal_com" type="host">pilot-payflowlink.paypal.com</value>
40+
</values>
41+
</policy>
42+
<policy id="form-action">
43+
<values>
44+
<value id="www_paypal" type="host">www.paypal.com</value>
45+
<value id="www_sandbox_paypal" type="host">www.sandbox.paypal.com</value>
46+
<value id="pilot_payflowlink_paypal_com" type="host">pilot-payflowlink.paypal.com</value>
3947
</values>
4048
</policy>
4149
</policies>

app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/iframe-methods.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ define([
7474
if (this.iframeIsLoaded) {
7575
document.getElementById(this.getCode() + '-iframe')
7676
.contentWindow.location.reload();
77+
this.paymentReady(false);
7778
}
7879

7980
this.paymentReady(true);

0 commit comments

Comments
 (0)