Skip to content

Commit 76f806e

Browse files
committed
Merge remote-tracking branch 'origin/2.4-develop' into pr_january_doleksandr
2 parents 19d4fa7 + 9e7230b commit 76f806e

File tree

26 files changed

+678
-80
lines changed

26 files changed

+678
-80
lines changed

app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateCustomDropDownOptionsActionGroup.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

@@ -20,6 +20,7 @@
2020
<argument name="secondOption" type="entity"/>
2121
</arguments>
2222

23+
<waitForElementClickable stepKey="waitForAddOptions" selector="{{AdminProductCustomizableOptionsSection.addOptionBtn}}"/>
2324
<click stepKey="clickAddOptions" selector="{{AdminProductCustomizableOptionsSection.addOptionBtn}}"/>
2425
<waitForPageLoad stepKey="waitForAddProductPageLoad"/>
2526

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
4+
* Copyright 2024 Adobe
5+
* All rights reserved.
56
* See COPYING.txt for license details.
67
*/
78
-->
@@ -43,5 +44,6 @@
4344
<element name="customAttribute" type="text" selector="input.admin__control-text[name='{{var}}']" parameterized="true"/>
4445
<element name="crossSellFilters" type="button" selector="//*[contains(@class, 'crosssell_product')]//button[text()='Filters']"/>
4546
<element name="upSellFilters" type="button" selector="//*[contains(@class, 'upsell_product')]//button[text()='Filters']"/>
47+
<element name="removeFilters" type="button" selector="(//button[contains(@class, 'action-remove')])[1]"/>
4648
</section>
4749
</sections>

app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateSimpleProductWithCustomOptionsDragNDropPerPageTest.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

@@ -18,8 +18,11 @@
1818
<testCaseId value="AC-6086"/>
1919
<useCaseId value="ACP2E-980"/>
2020
<group value="SimpleProduct"/>
21+
<group value="pr_exclude"/>
2122
</annotations>
2223

24+
<scrollTo selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" stepKey="scrollToCustomOptions"/>
25+
2326
<!-- Create two more custom options with 2 values -->
2427
<actionGroup ref="AdminCreateCustomDropDownOptionsActionGroup" stepKey="createSecondCustomOption">
2528
<argument name="customOptionName" value="{{ProductOptionDropDown.title}}2"/>

app/code/Magento/CatalogRule/Test/Mftf/Test/CatalogPriceRuleAndCustomerGroupMembershipArePersistedUnderLongTermCookieTest.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2018 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

@@ -96,6 +96,7 @@
9696
<argument name="categoryUrl" value="$createCategory.custom_attributes[url_key]$"/>
9797
<argument name="productName" value="$createProduct.name$"/>
9898
</actionGroup>
99+
<waitForPageLoad time="30" stepKey="waitFormReload"/>
99100
<dontSeeElement selector="{{StorefrontCategoryProductSection.ProductCatalogRuleSpecialPriceTitleByName($createProduct.name$)}}" stepKey="dontSeeSpecialPrice"/>
100101
</test>
101102
</tests>

app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminAddingNewOptionsWithImagesAndPricesToConfigurableProductTest.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

@@ -114,6 +114,10 @@
114114
<actionGroup ref="CliIndexerReindexActionGroup" stepKey="runCronIndex">
115115
<argument name="indices" value=""/>
116116
</actionGroup>
117+
<!--Clean cache-->
118+
<actionGroup ref="CliCacheCleanActionGroup" stepKey="flushCache">
119+
<argument name="tags" value=""/>
120+
</actionGroup>
117121
<!--Go to frontend and check image and price-->
118122
<amOnPage url="{{StorefrontProductPage.url($$createConfigProductCreateConfigurableProduct.custom_attributes[url_key]$$)}}" stepKey="goToProductPage"/>
119123

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*/
7+
-->
8+
9+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
11+
<actionGroup name="StorefrontSignUpForNewsLetterActionGroup">
12+
<annotations>
13+
<description>Checks the Newsletter Sign-Up checkbox</description>
14+
</annotations>
15+
<checkOption selector="{{StorefrontCustomerCreateFormSection.signUpForNewsletter}}" stepKey="checkSignUpForNewsletter"/>
16+
</actionGroup>
17+
</actionGroups>

app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerOnStorefrontSignupNewsletterTest.xml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

@@ -32,9 +32,12 @@
3232
</after>
3333

3434
<!--Create new customer on storefront and signup news letter-->
35-
<actionGroup ref="StorefrontCreateCustomerSignedUpNewsletterActionGroup" stepKey="createCustomer">
36-
<argument name="customer" value="CustomerEntityOne" />
35+
<actionGroup ref="StorefrontOpenCustomerAccountCreatePageActionGroup" stepKey="openCreateAccountPage"/>
36+
<actionGroup ref="StorefrontFillCustomerAccountCreationFormActionGroup" stepKey="createCustomer">
37+
<argument name="customer" value="CustomerEntityOne"/>
3738
</actionGroup>
39+
<actionGroup ref="StorefrontSignUpForNewsLetterActionGroup" stepKey="clickOnSignUpButton"/>
40+
<actionGroup ref="StorefrontClickCreateAnAccountCustomerAccountCreationFormActionGroup" stepKey="submitCreateAccountForm"/>
3841

3942
<!--Assert verify created new customer in grid-->
4043
<actionGroup ref="AdminOpenCustomersGridActionGroup" stepKey="navigateToCustomers"/>

app/code/Magento/Paypal/Test/Mftf/Test/AdminCaptureInvoiceForPaypalBillingAgreementTest.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
8+
89
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
910
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
1011
<test name="AdminCaptureInvoiceForPaypalBillingAgreementTest">
@@ -16,6 +17,7 @@
1617
<severity value="MAJOR"/>
1718
<testCaseId value="AC-4942"/>
1819
<group value="3rd_party_integration"/>
20+
<group value="pr_exclude"/>
1921
</annotations>
2022
<before>
2123
<!-- Simple product is created -->
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Persistent\Model;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\Model\ResourceModel\Db\VersionControl\Snapshot;
12+
use Magento\Store\Api\Data\StoreInterface;
13+
use Magento\Store\Model\StoreManagerInterface;
14+
use Magento\Persistent\Model\ResourceModel\ExpiredPersistentQuotesCollection;
15+
use Magento\Quote\Model\QuoteRepository;
16+
use Psr\Log\LoggerInterface;
17+
use Exception;
18+
19+
/**
20+
* Cleaning expired persistent quotes from the cron
21+
*/
22+
class CleanExpiredPersistentQuotes
23+
{
24+
/**
25+
* @param StoreManagerInterface $storeManager
26+
* @param ExpiredPersistentQuotesCollection $expiredPersistentQuotesCollection
27+
* @param QuoteRepository $quoteRepository
28+
* @param Snapshot $snapshot
29+
* @param LoggerInterface $logger
30+
* @param int $batchSize
31+
*/
32+
public function __construct(
33+
private readonly StoreManagerInterface $storeManager,
34+
private readonly ExpiredPersistentQuotesCollection $expiredPersistentQuotesCollection,
35+
private readonly QuoteRepository $quoteRepository,
36+
private readonly Snapshot $snapshot,
37+
private readonly LoggerInterface $logger,
38+
private readonly int $batchSize
39+
) {
40+
}
41+
42+
/**
43+
* Execute the cron job
44+
*
45+
* @param int $websiteId
46+
* @return void
47+
* @throws LocalizedException
48+
*/
49+
public function execute(int $websiteId): void
50+
{
51+
$stores = $this->storeManager->getWebsite($websiteId)->getStores();
52+
foreach ($stores as $store) {
53+
$this->processStoreQuotes($store);
54+
}
55+
}
56+
57+
/**
58+
* Process store quotes in batches
59+
*
60+
* @param StoreInterface $store
61+
* @return void
62+
*/
63+
private function processStoreQuotes(StoreInterface $store): void
64+
{
65+
$lastProcessedId = $count = 0;
66+
67+
while (true) {
68+
$quotesToProcess = $this->expiredPersistentQuotesCollection
69+
->getExpiredPersistentQuotes($store, $lastProcessedId, $this->batchSize);
70+
71+
if (!$quotesToProcess->count()) {
72+
break;
73+
}
74+
75+
foreach ($quotesToProcess as $quote) {
76+
$count++;
77+
try {
78+
$this->quoteRepository->delete($quote);
79+
$lastProcessedId = (int)$quote->getId();
80+
} catch (Exception $e) {
81+
$this->logger->error(sprintf(
82+
'Unable to delete expired quote (ID: %s): %s',
83+
$quote->getId(),
84+
(string)$e
85+
));
86+
}
87+
if ($count % $this->batchSize === 0) {
88+
$this->snapshot->clear($quote);
89+
}
90+
$quote->clearInstance();
91+
unset($quote);
92+
}
93+
94+
$quotesToProcess->clear();
95+
unset($quotesToProcess);
96+
}
97+
}
98+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Persistent\Model\ResourceModel;
9+
10+
use Magento\Framework\DB\Select;
11+
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
12+
use Magento\Persistent\Helper\Data;
13+
use Magento\Framework\App\Config\ScopeConfigInterface;
14+
use Magento\Quote\Model\ResourceModel\Quote\Collection;
15+
use Magento\Quote\Model\ResourceModel\Quote\CollectionFactory;
16+
use Magento\Store\Api\Data\StoreInterface;
17+
use Magento\Store\Model\ScopeInterface;
18+
19+
/**
20+
* Handles the collection of expired persistent quotes.
21+
*/
22+
class ExpiredPersistentQuotesCollection
23+
{
24+
/**
25+
* @param ScopeConfigInterface $scopeConfig
26+
* @param CollectionFactory $quoteCollectionFactory
27+
*/
28+
public function __construct(
29+
private readonly ScopeConfigInterface $scopeConfig,
30+
private readonly CollectionFactory $quoteCollectionFactory
31+
) {
32+
}
33+
34+
/**
35+
* Retrieves the collection of expired persistent quotes.
36+
*
37+
* Filters and returns all quotes that have expired based on the persistent lifetime threshold.
38+
*
39+
* @param StoreInterface $store
40+
* @param int $lastId
41+
* @param int $batchSize
42+
* @return AbstractCollection
43+
*/
44+
public function getExpiredPersistentQuotes(StoreInterface $store, int $lastId, int $batchSize): AbstractCollection
45+
{
46+
$lifetime = $this->scopeConfig->getValue(
47+
Data::XML_PATH_LIFE_TIME,
48+
ScopeInterface::SCOPE_WEBSITE,
49+
$store->getWebsiteId()
50+
);
51+
52+
$lastLoginCondition = gmdate("Y-m-d H:i:s", time() - $lifetime);
53+
54+
/** @var $quotes Collection */
55+
$quotes = $this->quoteCollectionFactory->create();
56+
57+
$additionalQuotes = clone $quotes;
58+
$additionalQuotes->addFieldToFilter('main_table.store_id', (int)$store->getId());
59+
$additionalQuotes->addFieldToFilter('main_table.updated_at', ['lt' => $lastLoginCondition]);
60+
$additionalQuotes->addFieldToFilter('main_table.is_persistent', 1);
61+
$additionalQuotes->addFieldToFilter('main_table.entity_id', ['gt' => $lastId]);
62+
$additionalQuotes->setOrder('entity_id', Collection::SORT_ORDER_ASC);
63+
$additionalQuotes->setPageSize($batchSize);
64+
65+
$select1 = clone $additionalQuotes->getSelect();
66+
$select2 = clone $additionalQuotes->getSelect();
67+
68+
//case 1 - customer logged in and logged out
69+
$select1->reset(Select::COLUMNS)
70+
->columns('main_table.entity_id')
71+
->joinLeft(
72+
['cl1' => $additionalQuotes->getTable('customer_log')],
73+
'cl1.customer_id = main_table.customer_id',
74+
[]
75+
)->where('cl1.last_login_at < cl1.last_logout_at
76+
AND cl1.last_logout_at IS NOT NULL');
77+
78+
//case 2 - customer logged in and not logged out but session expired
79+
//case 3 - customer logged in, logged out, logged in and then session expired
80+
$select2->reset(Select::COLUMNS)
81+
->columns('main_table.entity_id')
82+
->joinLeft(
83+
['cl2' => $additionalQuotes->getTable('customer_log')],
84+
'cl2.customer_id = main_table.customer_id',
85+
[]
86+
)->where('cl2.last_login_at < "' . $lastLoginCondition . '"
87+
AND (cl2.last_logout_at IS NULL OR cl2.last_login_at > cl2.last_logout_at)');
88+
89+
$selectQuoteIds = $additionalQuotes
90+
->getConnection()
91+
->select()
92+
->union(
93+
[
94+
$select1,
95+
$select2
96+
],
97+
Select::SQL_UNION_ALL
98+
);
99+
100+
$quotes->getSelect()->where('main_table.entity_id IN (' . $selectQuoteIds . ')');
101+
102+
return $quotes;
103+
}
104+
}

0 commit comments

Comments
 (0)