Skip to content

Commit 52f4632

Browse files
authored
Merge pull request #9949 from adobe-commerce-tier-4/PR_2025_07_18_chittima
[Support Tier-4 chittima] 07-18-2025 Regular delivery of bugfixes and improvements
2 parents 21390c6 + 86ebb81 commit 52f4632

File tree

25 files changed

+3140
-157
lines changed

25 files changed

+3140
-157
lines changed

app/code/Magento/CatalogImportExport/Model/Import/Product.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,10 +1688,11 @@ protected function _saveProducts()
16881688
}
16891689
$rowScope = $this->getRowScope($rowData);
16901690
$urlKey = $this->getUrlKey($rowData);
1691+
$rowSku = $rowData[self::COL_SKU];
16911692
if (!empty($rowData[self::URL_KEY])) {
16921693
// If url_key column and its value were in the CSV file
16931694
$rowData[self::URL_KEY] = $urlKey;
1694-
} elseif ($this->isNeedToChangeUrlKey($rowData)) {
1695+
} elseif ($this->isNeedToChangeUrlKey($rowData, isset($entityRowsIn[strtolower($rowSku)]))) {
16951696
// If url_key column was empty or even not declared in the CSV file but by the rules it needs
16961697
// to be settled. In case when url_key is generating from name column we have to ensure that
16971698
// the bunch of products will pass for the event with url_key column.
@@ -1701,7 +1702,6 @@ protected function _saveProducts()
17011702
// remove null byte character
17021703
$rowData[self::COL_NAME] = preg_replace(self::COL_NAME_FORMAT, '', $rowData[self::COL_NAME]);
17031704
}
1704-
$rowSku = $rowData[self::COL_SKU];
17051705
if (null === $rowSku) {
17061706
$this->getErrorAggregator()->addRowToSkip($rowNum);
17071707
continue;
@@ -3275,15 +3275,16 @@ protected function getResource()
32753275
* Whether a url key needs to change.
32763276
*
32773277
* @param array $rowData
3278+
* @param bool $hasParentRow
32783279
* @return bool
32793280
*/
3280-
private function isNeedToChangeUrlKey(array $rowData): bool
3281+
private function isNeedToChangeUrlKey(array $rowData, bool $hasParentRow = false): bool
32813282
{
32823283
$urlKey = $this->getUrlKey($rowData);
32833284
$productExists = $this->isSkuExist($rowData[self::COL_SKU]);
32843285
$markedToEraseUrlKey = isset($rowData[self::URL_KEY]);
32853286
// The product isn't new and the url key index wasn't marked for change.
3286-
if (!$urlKey && $productExists && !$markedToEraseUrlKey) {
3287+
if ($hasParentRow && empty($rowData[self::URL_KEY]) || !$urlKey && $productExists && !$markedToEraseUrlKey) {
32873288
// Seems there is no need to change the url key
32883289
return false;
32893290
}

app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
6-
*/
3+
/**
4+
* Copyright 2015 Adobe
5+
* All Rights Reserved.
6+
*/
77
-->
88
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
99
<argument name="data" xsi:type="array">
@@ -226,7 +226,6 @@
226226
<column name="dob" class="Magento\Ui\Component\Listing\Columns\Date" component="Magento_Ui/js/grid/columns/date" sortOrder="170">
227227
<settings>
228228
<timezone>false</timezone>
229-
<dateFormat>MMM d, y</dateFormat>
230229
<skipTimeZoneConversion>true</skipTimeZoneConversion>
231230
<filter>dateRange</filter>
232231
<dataType>date</dataType>

app/code/Magento/Indexer/etc/crontab.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2011 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
@@ -14,7 +14,7 @@
1414
<schedule>* * * * *</schedule>
1515
</job>
1616
<job name="indexer_clean_all_changelogs" instance="Magento\Indexer\Cron\ClearChangelog" method="execute">
17-
<schedule>0 * * * *</schedule>
17+
<schedule>*/5 * * * *</schedule>
1818
</job>
1919
</group>
2020
</config>

app/code/Magento/Paypal/Model/Payflow/Transparent.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ protected function createPaymentToken(Payment $payment, $token)
284284
*/
285285
private function getExpirationDate(Payment $payment)
286286
{
287-
$expDate = new \DateTime(
287+
$cardExpDate = new \DateTime(
288288
$payment->getCcExpYear()
289289
. '-'
290290
. $payment->getCcExpMonth()
@@ -294,8 +294,13 @@ private function getExpirationDate(Payment $payment)
294294
. '00:00:00',
295295
new \DateTimeZone('UTC')
296296
);
297-
$expDate->add(new \DateInterval('P1M'));
298-
return $expDate->format('Y-m-d 00:00:00');
297+
$cardExpDate->add(new \DateInterval('P1M'));
298+
$oneYearFromNow = new \DateTime('now', new \DateTimeZone('UTC'));
299+
$oneYearFromNow->add(new \DateInterval('P1Y'));
300+
if ($cardExpDate <= $oneYearFromNow) {
301+
return $cardExpDate->format('Y-m-d 00:00:00');
302+
}
303+
return $oneYearFromNow->format('Y-m-d 00:00:00');
299304
}
300305

301306
/**

app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php

Lines changed: 44 additions & 21 deletions
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 2015 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -117,10 +117,12 @@ protected function setUp(): void
117117
*
118118
* @dataProvider captureCorrectIdDataProvider
119119
* @param string $parentTransactionId
120+
* @param bool $createPaymentToken
120121
* @throws InvalidTransitionException
121122
* @throws LocalizedException
123+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
122124
*/
123-
public function testCaptureCorrectId(string $parentTransactionId)
125+
public function testCaptureCorrectId(string $parentTransactionId, bool $createPaymentToken)
124126
{
125127
if (empty($parentTransactionId)) {
126128
$setParentTransactionIdCalls = 1;
@@ -132,36 +134,54 @@ public function testCaptureCorrectId(string $parentTransactionId)
132134
$getGatewayTokenCalls = 0;
133135
}
134136

135-
$gatewayToken = 'gateway_token';
136-
$this->payment->expects($this->once())->method('getParentTransactionId')->willReturn($parentTransactionId);
137-
$this->payment->expects($this->exactly($setParentTransactionIdCalls))->method('setParentTransactionId');
138-
$this->payment->expects($this->exactly($setAdditionalInformationCalls))
139-
->method('setAdditionalInformation')
140-
->with(Payflowpro::PNREF, $gatewayToken);
141-
$this->payment->expects($this->exactly(4))
137+
$this->payment->expects($this->any())
142138
->method('getAdditionalInformation')
143-
->willReturnCallback(function ($args) {
139+
->willReturnCallback(function ($args) use ($createPaymentToken) {
144140
static $callCount = 0;
145141
if ($callCount == 0 && $args == 'result_code') {
146142
$callCount++;
147143
return 0;
148-
} elseif ($callCount == 1 && $args == Payflowpro::PNREF) {
144+
} elseif ($callCount == 1 && $args == Payflowpro::PNREF && !$createPaymentToken) {
149145
$callCount++;
150146
return '';
147+
} elseif ($callCount == 1 && $args == Payflowpro::PNREF && $createPaymentToken) {
148+
$callCount++;
149+
return 'ABCD';
151150
} elseif ($callCount == 2 && $args == Payflowpro::PNREF) {
152151
$callCount++;
153152
return Payflowpro::PNREF;
154153
} elseif ($callCount == 3 && $args == Payflowpro::PNREF) {
155154
$callCount++;
156155
return Payflowpro::PNREF;
156+
} elseif ($args == PayPalPayflowTransparent::CC_DETAILS && $createPaymentToken) {
157+
return json_encode([]);
157158
}
158159
});
159-
$this->paymentExtensionAttributes->expects($this->once())
160-
->method('getVaultPaymentToken')
161-
->willReturn($this->paymentToken);
162-
$this->paymentToken->expects($this->exactly($getGatewayTokenCalls))
163-
->method('getGatewayToken')
164-
->willReturn($gatewayToken);
160+
161+
$gatewayToken = 'gateway_token';
162+
if ($createPaymentToken) {
163+
$this->payment->expects($this->never())->method('setParentTransactionId');
164+
$this->payment->expects($this->never())
165+
->method('setAdditionalInformation');
166+
$this->paymentExtensionAttributes->expects($this->once())
167+
->method('getVaultPaymentToken')
168+
->willReturn(null);
169+
$this->paymentToken->expects($this->never())
170+
->method('getGatewayToken')
171+
->willReturn($gatewayToken);
172+
} else {
173+
$this->payment->expects($this->once())->method('getParentTransactionId')->willReturn($parentTransactionId);
174+
$this->payment->expects($this->exactly($setParentTransactionIdCalls))->method('setParentTransactionId');
175+
$this->payment->expects($this->exactly($setAdditionalInformationCalls))
176+
->method('setAdditionalInformation')
177+
->with(Payflowpro::PNREF, $gatewayToken);
178+
$this->paymentExtensionAttributes->expects($this->once())
179+
->method('getVaultPaymentToken')
180+
->willReturn($this->paymentToken);
181+
$this->paymentToken->expects($this->exactly($getGatewayTokenCalls))
182+
->method('getGatewayToken')
183+
->willReturn($gatewayToken);
184+
}
165185

166186
$this->subject->capture($this->payment, 100);
167187
}
@@ -174,8 +194,10 @@ public function testCaptureCorrectId(string $parentTransactionId)
174194
public static function captureCorrectIdDataProvider(): array
175195
{
176196
return [
177-
'No Transaction ID' => [''],
178-
'With Transaction ID' => ['1'],
197+
['', false],
198+
['1', false],
199+
['', true],
200+
['1', true],
179201
];
180202
}
181203

@@ -387,7 +409,8 @@ private function initPayment()
387409
'getParentTransactionId',
388410
'setParentTransactionId',
389411
'setAdditionalInformation',
390-
'getAdditionalInformation'
412+
'getAdditionalInformation',
413+
'setExtensionAttributes'
391414
]
392415
)
393416
->getMock();
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\QuoteGraphQl\Model;
9+
10+
use Magento\Framework\Exception\AuthorizationException;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\GraphQl\Config\Element\Field;
13+
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
14+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
15+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
16+
use Magento\GraphQl\Helper\Error\AggregateExceptionMessageFormatter;
17+
18+
class OrderErrorProcessor
19+
{
20+
/**
21+
* @param AggregateExceptionMessageFormatter $errorMessageFormatter
22+
* @param ErrorMapper $errorMapper
23+
*/
24+
public function __construct(
25+
private readonly AggregateExceptionMessageFormatter $errorMessageFormatter,
26+
private readonly ErrorMapper $errorMapper
27+
) {
28+
}
29+
30+
/**
31+
* Process exception thrown by ordering process
32+
*
33+
* @param LocalizedException $exception
34+
* @param Field $field
35+
* @param ContextInterface $context
36+
* @param ResolveInfo $info
37+
* @throws GraphQlAuthorizationException
38+
* @throws QuoteException
39+
*/
40+
public function execute(
41+
LocalizedException $exception,
42+
Field $field,
43+
ContextInterface $context,
44+
ResolveInfo $info
45+
): void {
46+
$exception = $this->errorMessageFormatter->getFormatted(
47+
$exception,
48+
__('A server error stopped your order from being placed. ' .
49+
'Please try to place your order again'),
50+
'Unable to place order',
51+
$field,
52+
$context,
53+
$info
54+
);
55+
$exceptionCode = $exception->getCode();
56+
if (!$exceptionCode) {
57+
$exceptionCode = $this->errorMapper->getErrorMessageId($exception->getRawMessage());
58+
}
59+
60+
throw new QuoteException(__($exception->getMessage()), $exception, $exceptionCode);
61+
}
62+
}

app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,14 @@
1414
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1515
use Magento\Framework\GraphQl\Query\ResolverInterface;
1616
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
17-
use Magento\GraphQl\Helper\Error\AggregateExceptionMessageFormatter;
1817
use Magento\QuoteGraphQl\Model\Cart\GetCartForCheckout;
1918
use Magento\QuoteGraphQl\Model\Cart\PlaceOrder as PlaceOrderModel;
20-
use Magento\QuoteGraphQl\Model\ErrorMapper;
21-
use Magento\QuoteGraphQl\Model\QuoteException;
19+
use Magento\QuoteGraphQl\Model\OrderErrorProcessor;
2220
use Magento\Sales\Api\OrderRepositoryInterface;
2321
use Magento\SalesGraphQl\Model\Formatter\Order as OrderFormatter;
2422

2523
/**
2624
* Resolver for placing order after payment method has already been set
27-
*
28-
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2925
*/
3026
class PlaceOrder implements ResolverInterface
3127
{
@@ -34,16 +30,14 @@ class PlaceOrder implements ResolverInterface
3430
* @param PlaceOrderModel $placeOrder
3531
* @param OrderRepositoryInterface $orderRepository
3632
* @param OrderFormatter $orderFormatter
37-
* @param AggregateExceptionMessageFormatter $errorMessageFormatter
38-
* @param ErrorMapper $errorMapper
33+
* @param OrderErrorProcessor $orderErrorProcessor
3934
*/
4035
public function __construct(
4136
private readonly GetCartForCheckout $getCartForCheckout,
4237
private readonly PlaceOrderModel $placeOrder,
4338
private readonly OrderRepositoryInterface $orderRepository,
4439
private readonly OrderFormatter $orderFormatter,
45-
private readonly AggregateExceptionMessageFormatter $errorMessageFormatter,
46-
private readonly ErrorMapper $errorMapper
40+
private readonly OrderErrorProcessor $orderErrorProcessor
4741
) {
4842
}
4943

@@ -59,29 +53,15 @@ public function resolve(Field $field, $context, ResolveInfo $info, ?array $value
5953
$maskedCartId = $args['input']['cart_id'];
6054
$userId = (int)$context->getUserId();
6155
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
56+
$order = null;
6257
try {
6358
$cart = $this->getCartForCheckout->execute($maskedCartId, $userId, $storeId);
6459
$orderId = $this->placeOrder->execute($cart, $maskedCartId, $userId);
6560
$order = $this->orderRepository->get($orderId);
6661
} catch (AuthorizationException $exception) {
67-
throw new GraphQlAuthorizationException(
68-
__($exception->getMessage())
69-
);
62+
throw new GraphQlAuthorizationException(__($exception->getMessage()));
7063
} catch (LocalizedException $exception) {
71-
$exception = $this->errorMessageFormatter->getFormatted(
72-
$exception,
73-
__('A server error stopped your order from being placed. Please try to place your order again'),
74-
'Unable to place order',
75-
$field,
76-
$context,
77-
$info
78-
);
79-
$exceptionCode = $exception->getCode();
80-
if (!$exceptionCode) {
81-
$exceptionCode = $this->errorMapper->getErrorMessageId($exception->getRawMessage());
82-
}
83-
84-
throw new QuoteException(__($exception->getMessage()), $exception, $exceptionCode);
64+
$this->orderErrorProcessor->execute($exception, $field, $context, $info);
8565
}
8666

8767
return [

0 commit comments

Comments
 (0)