Skip to content

Commit 2a252ae

Browse files
Merge pull request #9887 from adobe-commerce-tier-4/PR_25_June_odubovyk
[Support Tier-4 odubovyk] 06-25-2025 Regular delivery of bugfixes and improvements
2 parents 3641e45 + 88e78a0 commit 2a252ae

File tree

5 files changed

+142
-19
lines changed

5 files changed

+142
-19
lines changed

app/code/Magento/Directory/Test/Unit/Model/CurrencyTest.php

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,15 @@ function (array $args) {
138138
*/
139139
public static function getOutputFormatDataProvider(): array
140140
{
141-
$ar_DZ = "\u{062C}.\u{0645}.\u{200F}\u{00A0}%s";
142-
if (version_compare(PHP_VERSION, '8.3', '>=')) {
143-
$ar_DZ = "%s\u{00A0}\u{062C}.\u{0645}.\u{200F}";
144-
}
141+
// Use dynamic detection for problematic locale/currency combinations!
142+
$ar_DZ_EGP = self::getExpectedFormatForLocale('ar_DZ', 'EGP');
143+
145144
return [
146145
'en_US:USD' => ['en_US', 'USD', '$%s'],
147146
'en_US:PLN' => ['en_US', 'PLN', "PLN\u{00A0}%s"],
148147
'en_US:PKR' => ['en_US', 'PKR', "PKR\u{00A0}%s"],
149148
'af_ZA:VND' => ['af_ZA', 'VND', "\u{20AB}%s"],
150-
'ar_DZ:EGP' => ['ar_DZ', 'EGP', $ar_DZ],
149+
'ar_DZ:EGP' => ['ar_DZ', 'EGP', $ar_DZ_EGP],
151150
'ar_SA:USD' => ['ar_SA', 'USD', "%s\u{00A0}US$"],
152151
'ar_SA:LBP' => ['ar_SA', 'LBP', "%s\u{00A0}\u{0644}.\u{0644}.\u{200F}"],
153152
'fa_IR:USD' => ['fa_IR', 'USD', "\u{200E}$%s"],
@@ -162,6 +161,62 @@ public static function getOutputFormatDataProvider(): array
162161
];
163162
}
164163

164+
/**
165+
* Get expected format for a specific locale/currency combination
166+
* This handles cases where intl extension version affects formatting
167+
*
168+
* @param string $locale
169+
* @param string $currency
170+
* @return string
171+
*/
172+
private static function getExpectedFormatForLocale(string $locale, string $currency): string
173+
{
174+
// Define known problematic combinations and their expected formats
175+
$problematicFormats = [
176+
'ar_DZ:EGP' => [
177+
'old' => "\u{062C}.\u{0645}.\u{200F}\u{00A0}%s",
178+
'new' => "%s\u{00A0}\u{062C}.\u{0645}.\u{200F}"
179+
]
180+
];
181+
182+
$key = $locale . ':' . $currency;
183+
184+
if (isset($problematicFormats[$key])) {
185+
// Check if we're using a newer intl version that changes formatting
186+
if (self::isNewerIntlVersion()) {
187+
return $problematicFormats[$key]['new'];
188+
}
189+
return $problematicFormats[$key]['old'];
190+
}
191+
192+
// For non-problematic combinations, return a default format
193+
// This could be enhanced with more specific formats as needed
194+
return "%s";
195+
}
196+
197+
/**
198+
* Check if the current intl extension version uses newer formatting rules
199+
*
200+
* @return bool
201+
*/
202+
private static function isNewerIntlVersion(): bool
203+
{
204+
// Check intl extension version
205+
if (extension_loaded('intl')) {
206+
$intlVersion = INTL_ICU_VERSION ?? '0.0.0';
207+
208+
// ICU 72+ (released around 2022) introduced changes to RTL formatting
209+
// This is a more reliable indicator than PHP version
210+
if (version_compare($intlVersion, '72.0', '>=')) {
211+
return true;
212+
}
213+
}
214+
215+
// Fallback: Check PHP version as a rough indicator
216+
// This is less reliable but provides some backward compatibility
217+
return version_compare(PHP_VERSION, '8.3', '>=');
218+
}
219+
165220
/**
166221
* @dataProvider getFormatTxtNumberFormatterDataProvider
167222
* @param string $locale

app/code/Magento/Sales/Model/Order.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -887,8 +887,16 @@ public function canShip()
887887
private function checkItemShipping(): bool
888888
{
889889
foreach ($this->getAllItems() as $item) {
890-
$qtyToShip = !$item->getParentItem() || $item->getParentItem()->getProductType() !== Type::TYPE_BUNDLE ?
891-
$item->getQtyToShip() : $item->getSimpleQtyToShip();
890+
if (!$item->getParentItem() || $item->getParentItem()->getProductType() !== Type::TYPE_BUNDLE) {
891+
$qtyToShip = $item->getQtyToShip();
892+
} else {
893+
if ($item->getParentItem()->getProductType() === Type::TYPE_BUNDLE &&
894+
$item->getParentItem()->getProduct()->getShipmentType() == Type\AbstractType::SHIPMENT_TOGETHER) {
895+
$qtyToShip = $item->getParentItem()->getQtyToShip();
896+
} else {
897+
$qtyToShip = $item->getSimpleQtyToShip();
898+
}
899+
}
892900

893901
if ($qtyToShip > 0 && !$item->getIsVirtual() && !$item->getLockedDoShip()) {
894902
return true;

app/code/Magento/Sales/Test/Unit/Model/OrderTest.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2013 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

88
namespace Magento\Sales\Test\Unit\Model;
99

1010
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Catalog\Model\Product\Type;
1113
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
1214
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
1315
use Magento\Framework\Api\SearchCriteria;
@@ -213,6 +215,49 @@ protected function setUp(): void
213215
);
214216
}
215217

218+
/**
219+
* @return void
220+
* @throws \PHPUnit\Framework\MockObject\Exception
221+
*/
222+
public function testCanShipBundleWithToghetherShipment(): void
223+
{
224+
$this->order->setActionFlag($this->order::ACTION_FLAG_UNHOLD, false);
225+
$this->order->setActionFlag($this->order::ACTION_FLAG_SHIP, true);
226+
227+
$bundleItem = $this->createMock(Item::class);
228+
$bundleItem->expects($this->any())->method('getParentItem')->willReturn(null);
229+
$bundleItem->expects($this->exactly(2))->method('getQtyToShip')->willReturn(0);
230+
$bundleItem->expects($this->any())->method('getProductType')->willReturn(Type::TYPE_BUNDLE);
231+
232+
$product = $this->getMockBuilder(Product::class)
233+
->disableOriginalConstructor()
234+
->addMethods(['getShipmentType'])
235+
->getMock();
236+
$product->expects($this->any())
237+
->method('getShipmentType')
238+
->willReturn(Type\AbstractType::SHIPMENT_TOGETHER);
239+
$bundleItem->expects($this->any())->method('getProduct')->willReturn($product);
240+
241+
$childProduct = $this->createMock(Item::class);
242+
$childProduct->expects($this->any())->method('getParentItem')->willReturn($bundleItem);
243+
244+
$orderItems = [$bundleItem, $childProduct];
245+
$this->searchCriteriaBuilder->expects($this->once())->method('addFilter')->willReturnSelf();
246+
247+
$searchCriteria = $this->getMockBuilder(SearchCriteria::class)
248+
->disableOriginalConstructor()
249+
->getMockForAbstractClass();
250+
$this->searchCriteriaBuilder->expects($this->once())->method('create')->willReturn($searchCriteria);
251+
$itemsCollection = $this->getMockBuilder(OrderItemSearchResultInterface::class)
252+
->onlyMethods(['getItems'])
253+
->disableOriginalConstructor()
254+
->getMockForAbstractClass();
255+
$itemsCollection->expects($this->once())->method('getItems')->willReturn($orderItems);
256+
$this->itemRepository->expects($this->once())->method('getList')->willReturn($itemsCollection);
257+
258+
$this->assertFalse($this->order->canShip());
259+
}
260+
216261
/**
217262
* Test testGetItems method.
218263
*/

app/code/Magento/WishlistGraphQl/Model/Resolver/WishlistItems.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function resolve(
6161
$wishlist = $value['model'];
6262

6363
if ($context->getExtensionAttributes()->getStore() instanceof StoreInterface) {
64-
$args['store_id'] = $context->getExtensionAttributes()->getStore()->getId();
64+
$args['website_id'] = $context->getExtensionAttributes()->getStore()->getWebsiteId();
6565
}
6666

6767
/** @var WishlistItemCollection $wishlistItemCollection */
@@ -95,6 +95,7 @@ public function resolve(
9595
* @param Wishlist $wishlist
9696
* @param array $args
9797
* @return WishlistItemCollection
98+
* @throws LocalizedException
9899
*/
99100
private function getWishListItems(Wishlist $wishlist, array $args): WishlistItemCollection
100101
{
@@ -104,8 +105,15 @@ private function getWishListItems(Wishlist $wishlist, array $args): WishlistItem
104105
/** @var WishlistItemCollection $wishlistItemCollection */
105106
$wishlistItemCollection = $this->wishlistItemCollectionFactory->create();
106107
$wishlistItemCollection->addWishlistFilter($wishlist);
107-
if (isset($args['store_id'])) {
108-
$wishlistItemCollection->addStoreFilter($args['store_id']);
108+
if (isset($args['website_id']) && $args['website_id']) {
109+
$website = $this->storeManager->getWebsite($args['website_id']);
110+
$stores = [];
111+
foreach ($website->getStores() as $store) {
112+
$stores[] = $store->getId();
113+
}
114+
if ($stores) {
115+
$wishlistItemCollection->addStoreFilter($stores);
116+
}
109117
} else {
110118
$wishlistItemCollection->addStoreFilter(array_map(function (StoreInterface $store) {
111119
return $store->getId();

app/code/Magento/WishlistGraphQl/Test/Unit/Model/Resolver/WishlistItemsTest.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
namespace Magento\WishlistGraphQl\Test\Unit\Model\Resolver;
99

1010
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
11+
use Magento\GraphQl\Model\Query\ContextExtensionInterface;
1112
use Magento\GraphQl\Model\Query\ContextInterface;
1213
use Magento\Framework\GraphQl\Config\Element\Field;
13-
use Magento\GraphQl\Model\Query\ContextExtensionInterface;
1414
use Magento\Store\Api\Data\StoreInterface;
1515
use Magento\Store\Model\StoreManagerInterface;
16+
use Magento\Store\Model\Website;
1617
use Magento\Wishlist\Model\ResourceModel\Item;
1718
use Magento\Wishlist\Model\ResourceModel\Item\Collection as WishlistItemCollection;
1819
use Magento\Wishlist\Model\ResourceModel\Item\CollectionFactory as WishlistItemCollectionFactory;
@@ -21,6 +22,9 @@
2122
use PHPUnit\Framework\MockObject\MockObject;
2223
use PHPUnit\Framework\TestCase;
2324

25+
/**
26+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
27+
*/
2428
class WishlistItemsTest extends TestCase
2529
{
2630
/**
@@ -49,14 +53,13 @@ protected function setUp(): void
4953
*/
5054
public function testResolve(): void
5155
{
52-
$storeId = $itemId = 1;
56+
$webId = $storeId = $itemId = 1;
5357

5458
$field = $this->createMock(Field::class);
55-
$context = $this->getMockBuilder(ContextInterface::class)
56-
->disableOriginalConstructor()
57-
->getMock();
59+
$context = $this->createMock(ContextInterface::class);
5860
$store = $this->createMock(StoreInterface::class);
59-
$store->expects($this->once())->method('getId')->willReturn($storeId);
61+
$store->expects($this->once())->method('getWebsiteId')->willReturn($webId);
62+
$store->expects($this->any())->method('getId')->willReturn($storeId);
6063

6164
$extensionAttributes = $this->getMockBuilder(ContextExtensionInterface::class)
6265
->disableOriginalConstructor()
@@ -87,7 +90,7 @@ public function testResolve(): void
8790
->willReturnSelf();
8891
$wishlistCollection->expects($this->once())
8992
->method('addStoreFilter')
90-
->with($storeId)
93+
->with([$storeId])
9194
->willReturnSelf();
9295
$wishlistCollection->expects($this->once())->method('setVisibilityFilter')->willReturnSelf();
9396
$wishlistCollection->expects($this->once())->method('setCurPage')->willReturnSelf();
@@ -100,6 +103,10 @@ public function testResolve(): void
100103
->method('create')
101104
->willReturn($wishlistCollection);
102105

106+
$website = $this->createMock(Website::class);
107+
$website->expects($this->any())->method('getStores')->willReturn([$store]);
108+
$this->storeManager->expects($this->once())->method('getWebsite')->with($webId)->willReturn($website);
109+
103110
$resolver = new WishlistItems($this->wishlistItemCollectionFactory, $this->storeManager);
104111
$resolver->resolve($field, $context, $info, ['model' => $wishlist]);
105112
}

0 commit comments

Comments
 (0)