Skip to content

Commit 331dc74

Browse files
#39146: Image resize queue error due to .tmp file handling when deleting unsaved product images
- add new service class with unit test
1 parent 93c0caa commit 331dc74

File tree

5 files changed

+140
-22
lines changed

5 files changed

+140
-22
lines changed

app/code/Magento/Bundle/Model/Product/Price.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Magento\Framework\Pricing\PriceCurrencyInterface;
1010
use Magento\Framework\App\ObjectManager;
1111
use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory;
12+
use Magento\Catalog\Service\SpecialPriceService;
1213

1314
/**
1415
* Bundle product type price model
@@ -51,6 +52,12 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
5152
*/
5253
private $serializer;
5354

55+
56+
/**
57+
* @var SpecialPriceService
58+
*/
59+
protected SpecialPriceService $specialPriceService;
60+
5461
/**
5562
* Constructor
5663
*
@@ -66,6 +73,7 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
6673
* @param \Magento\Catalog\Helper\Data $catalogData
6774
* @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
6875
* @param ProductTierPriceExtensionFactory|null $tierPriceExtensionFactory
76+
* @param SpecialPriceService|null $specialPriceService
6977
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
7078
*/
7179
public function __construct(
@@ -80,11 +88,14 @@ public function __construct(
8088
\Magento\Framework\App\Config\ScopeConfigInterface $config,
8189
\Magento\Catalog\Helper\Data $catalogData,
8290
?\Magento\Framework\Serialize\Serializer\Json $serializer = null,
83-
?ProductTierPriceExtensionFactory $tierPriceExtensionFactory = null
91+
?ProductTierPriceExtensionFactory $tierPriceExtensionFactory = null,
92+
?SpecialPriceService $specialPriceService = null
8493
) {
8594
$this->_catalogData = $catalogData;
8695
$this->serializer = $serializer ?: ObjectManager::getInstance()
8796
->get(\Magento\Framework\Serialize\Serializer\Json::class);
97+
$this->specialPriceService = $specialPriceService ?: ObjectManager::getInstance()
98+
->get(SpecialPriceService::class);
8899
parent::__construct(
89100
$ruleFactory,
90101
$storeManager,
@@ -630,12 +641,7 @@ public function calculateSpecialPrice(
630641
) {
631642
if ($specialPrice !== null && $specialPrice != false) {
632643

633-
if ($specialPriceTo
634-
&& strtotime($specialPriceTo) !== false
635-
&& date('H:i:s', strtotime($specialPriceTo)) !== '00:00:00') {
636-
$dateToTimestamp = strtotime($specialPriceTo);
637-
$specialPriceTo = date('Y-m-d H:i:s', $dateToTimestamp - 86400);
638-
}
644+
$specialPriceTo = $this->specialPriceService->execute($specialPriceTo);
639645

640646
if ($this->_localeDate->isScopeDateInInterval($store, $specialPriceFrom, $specialPriceTo)) {
641647
$specialPrice = $finalPrice * ($specialPrice / 100);

app/code/Magento/Catalog/Model/Product/Type/Price.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory;
1616
use Magento\Framework\App\ObjectManager;
1717
use Magento\Store\Api\Data\WebsiteInterface;
18+
use Magento\Catalog\Service\SpecialPriceService;
1819

1920
/**
2021
* Product type price model
@@ -88,6 +89,11 @@ class Price implements ResetAfterRequestInterface
8889
*/
8990
private $tierPriceExtensionFactory;
9091

92+
/**
93+
* @var SpecialPriceService
94+
*/
95+
protected SpecialPriceService $specialPriceService;
96+
9197
/**
9298
* Constructor
9399
*
@@ -101,6 +107,7 @@ class Price implements ResetAfterRequestInterface
101107
* @param \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory
102108
* @param \Magento\Framework\App\Config\ScopeConfigInterface $config
103109
* @param ProductTierPriceExtensionFactory|null $tierPriceExtensionFactory
110+
* @param SpecialPriceService|null $specialPriceService
104111
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
105112
*/
106113
public function __construct(
@@ -113,7 +120,8 @@ public function __construct(
113120
GroupManagementInterface $groupManagement,
114121
\Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory,
115122
\Magento\Framework\App\Config\ScopeConfigInterface $config,
116-
?ProductTierPriceExtensionFactory $tierPriceExtensionFactory = null
123+
?ProductTierPriceExtensionFactory $tierPriceExtensionFactory = null,
124+
?SpecialPriceService $specialPriceService = null
117125
) {
118126
$this->_ruleFactory = $ruleFactory;
119127
$this->_storeManager = $storeManager;
@@ -126,6 +134,8 @@ public function __construct(
126134
$this->config = $config;
127135
$this->tierPriceExtensionFactory = $tierPriceExtensionFactory ?: ObjectManager::getInstance()
128136
->get(ProductTierPriceExtensionFactory::class);
137+
$this->specialPriceService = $specialPriceService ?: ObjectManager::getInstance()
138+
->get(SpecialPriceService::class);
129139
}
130140

131141
/**
@@ -643,12 +653,7 @@ public function calculateSpecialPrice(
643653
) {
644654
if ($specialPrice !== null && $specialPrice != false) {
645655

646-
if ($specialPriceTo
647-
&& strtotime($specialPriceTo) !== false
648-
&& date('H:i:s', strtotime($specialPriceTo)) !== '00:00:00') {
649-
$dateToTimestamp = strtotime($specialPriceTo);
650-
$specialPriceTo = date('Y-m-d H:i:s', $dateToTimestamp - 86400);
651-
}
656+
$specialPriceTo = $this->specialPriceService->execute($specialPriceTo);
652657

653658
if ($this->_localeDate->isScopeDateInInterval($store, $specialPriceFrom, $specialPriceTo)) {
654659
$finalPrice = min($finalPrice, (float) $specialPrice);

app/code/Magento/Catalog/Pricing/Price/SpecialPrice.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
namespace Magento\Catalog\Pricing\Price;
88

99
use Magento\Catalog\Model\Product;
10+
use Magento\Framework\App\ObjectManager;
1011
use Magento\Framework\Pricing\Adjustment\CalculatorInterface;
1112
use Magento\Framework\Pricing\Price\AbstractPrice;
1213
use Magento\Framework\Pricing\Price\BasePriceProviderInterface;
1314
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
1415
use Magento\Store\Api\Data\WebsiteInterface;
16+
use Magento\Catalog\Service\SpecialPriceService;
1517

1618
/**
1719
* Special price model
@@ -28,22 +30,31 @@ class SpecialPrice extends AbstractPrice implements SpecialPriceInterface, BaseP
2830
*/
2931
protected $localeDate;
3032

33+
/**
34+
* @var SpecialPriceService
35+
*/
36+
protected SpecialPriceService $specialPriceService;
37+
3138
/**
3239
* @param Product $saleableItem
3340
* @param float $quantity
3441
* @param CalculatorInterface $calculator
3542
* @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
3643
* @param TimezoneInterface $localeDate
44+
* @param SpecialPriceService|null $specialPriceService
3745
*/
3846
public function __construct(
3947
Product $saleableItem,
4048
$quantity,
4149
CalculatorInterface $calculator,
4250
\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
43-
TimezoneInterface $localeDate
51+
TimezoneInterface $localeDate,
52+
?SpecialPriceService $specialPriceService = null
4453
) {
4554
parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
4655
$this->localeDate = $localeDate;
56+
$this->specialPriceService = $specialPriceService ?: ObjectManager::getInstance()
57+
->get(SpecialPriceService::class);
4758
}
4859

4960
/**
@@ -103,13 +114,7 @@ public function getSpecialToDate()
103114
*/
104115
public function isScopeDateInInterval()
105116
{
106-
$dateTo = $this->getSpecialToDate();
107-
if ($dateTo
108-
&& strtotime($dateTo) !== false
109-
&& date('H:i:s', strtotime($dateTo)) !== '00:00:00') {
110-
$dateToTimestamp = strtotime($dateTo);
111-
$dateTo = date('Y-m-d H:i:s', $dateToTimestamp - 86400);
112-
}
117+
$dateTo = $this->specialPriceService->execute($this->getSpecialToDate());
113118

114119
return $this->localeDate->isScopeDateInInterval(
115120
WebsiteInterface::ADMIN_CODE,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Service;
9+
10+
/**
11+
* This class provides functionality to normalize the end date/time of special prices
12+
*/
13+
class SpecialPriceService
14+
{
15+
/**
16+
* This class subtracts one day from $dateTo if it contains a specific time (hours, minutes, seconds)
17+
* because \Magento\Framework\Stdlib\DateTime\Timezone::isScopeDateInInterval adds one day.
18+
* This ensures that the special price expires exactly at the specified time
19+
*
20+
* For example,
21+
* - If $dateTo is "2025-05-12 17:00:00", it will be converted to "2025-05-11 17:00:00"
22+
* - If $dateTo is "2024-05-12 00:00:00", it will remain unchanged
23+
*
24+
* @param mixed $dateTo
25+
* @return mixed|string
26+
*/
27+
public function execute(mixed $dateTo): mixed
28+
{
29+
if ($dateTo
30+
&& strtotime($dateTo) !== false
31+
&& date('H:i:s', strtotime($dateTo)) !== '00:00:00') {
32+
$dateToTimestamp = strtotime($dateTo);
33+
$dateTo = date('Y-m-d H:i:s', $dateToTimestamp - 86400);
34+
}
35+
36+
return $dateTo;
37+
}
38+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Test\Unit\Service;
9+
10+
use Magento\Catalog\Service\SpecialPriceService;
11+
use PHPUnit\Framework\TestCase;
12+
13+
/**
14+
* Test for SpecialPriceService
15+
*/
16+
class SpecialPriceServiceTest extends TestCase
17+
{
18+
/**
19+
* @var SpecialPriceService
20+
*/
21+
private SpecialPriceService $specialPriceService;
22+
23+
/**
24+
* Set up a test environment
25+
*/
26+
protected function setUp(): void
27+
{
28+
$this->specialPriceService = new SpecialPriceService();
29+
}
30+
31+
/**
32+
* Data provider for execute method test
33+
*
34+
* @return array
35+
*/
36+
public static function executeDataProvider(): array
37+
{
38+
return [
39+
'invalid_date' => [
40+
'dateTo' => 'some date to',
41+
'expected' => 'some date to'
42+
],
43+
'date_without_time' => [
44+
'dateTo' => '2025-05-12 00:00:00',
45+
'expected' => '2025-05-12 00:00:00'
46+
],
47+
'date_with_specific_time' => [
48+
'dateTo' => '2025-05-12 17:00:00',
49+
'expected' => '2025-05-11 17:00:00'
50+
]
51+
];
52+
}
53+
54+
/**
55+
* @dataProvider executeDataProvider
56+
* @param mixed $dateTo
57+
* @param mixed $expected
58+
*/
59+
public function testExecute(mixed $dateTo, mixed $expected): void
60+
{
61+
$result = $this->specialPriceService->execute($dateTo);
62+
$this->assertEquals($expected, $result);
63+
}
64+
}

0 commit comments

Comments
 (0)