Skip to content

Commit 5af7f5a

Browse files
committed
MC-36262: Incorrect order status label in sales update emails sent from the admin for non-default store views
1 parent 212d69a commit 5af7f5a

File tree

8 files changed

+246
-34
lines changed

8 files changed

+246
-34
lines changed

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
use Magento\Sales\Model\ResourceModel\Order\Shipment\Track\Collection as TrackCollection;
3232
use Magento\Sales\Model\ResourceModel\Order\Status\History\Collection as HistoryCollection;
3333
use Magento\Store\Model\ScopeInterface;
34+
use Magento\Framework\App\Area;
35+
use Magento\Sales\Model\Order\StatusLabel;
3436

3537
/**
3638
* Order model
@@ -324,6 +326,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface
324326
*/
325327
private $regionResource;
326328

329+
/**
330+
* @var StatusLabel
331+
*/
332+
private $statusLabel;
333+
327334
/**
328335
* @param \Magento\Framework\Model\Context $context
329336
* @param \Magento\Framework\Registry $registry
@@ -395,7 +402,8 @@ public function __construct(
395402
SearchCriteriaBuilder $searchCriteriaBuilder = null,
396403
ScopeConfigInterface $scopeConfig = null,
397404
RegionFactory $regionFactory = null,
398-
RegionResource $regionResource = null
405+
RegionResource $regionResource = null,
406+
StatusLabel $statusLabel = null
399407
) {
400408
$this->_storeManager = $storeManager;
401409
$this->_orderConfig = $orderConfig;
@@ -427,7 +435,7 @@ public function __construct(
427435
$this->regionFactory = $regionFactory ?: ObjectManager::getInstance()->get(RegionFactory::class);
428436
$this->regionResource = $regionResource ?: ObjectManager::getInstance()->get(RegionResource::class);
429437
$this->regionItems = [];
430-
438+
$this->statusLabel = $statusLabel ?: ObjectManager::getInstance()->get(StatusLabel::class);
431439
parent::__construct(
432440
$context,
433441
$registry,
@@ -1104,7 +1112,11 @@ public function setState($state)
11041112
*/
11051113
public function getFrontendStatusLabel()
11061114
{
1107-
return $this->getConfig()->getStatusFrontendLabel($this->getStatus());
1115+
return $this->statusLabel->getStatusFrontendLabel(
1116+
$this->getStatus(),
1117+
Area::AREA_FRONTEND,
1118+
$this->getStoreId()
1119+
);
11081120
}
11091121

11101122
/**
@@ -1115,7 +1127,7 @@ public function getFrontendStatusLabel()
11151127
*/
11161128
public function getStatusLabel()
11171129
{
1118-
return $this->getConfig()->getStatusLabel($this->getStatus());
1130+
return $this->statusLabel->getStatusLabel($this->getStatus());
11191131
}
11201132

11211133
/**

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

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
*/
66
namespace Magento\Sales\Model\Order;
77

8+
use Magento\Framework\App\Area;
89
use Magento\Framework\Exception\LocalizedException;
10+
use Magento\Framework\App\ObjectManager;
911

1012
/**
1113
* Order configuration model
@@ -51,27 +53,35 @@ class Config
5153
* @var array
5254
*/
5355
protected $maskStatusesMapping = [
54-
\Magento\Framework\App\Area::AREA_FRONTEND => [
56+
Area::AREA_FRONTEND => [
5557
\Magento\Sales\Model\Order::STATUS_FRAUD => \Magento\Sales\Model\Order::STATUS_FRAUD,
5658
\Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW => \Magento\Sales\Model\Order::STATE_PROCESSING
5759
]
5860
];
5961

62+
/**
63+
* @var StatusLabel
64+
*/
65+
private $statusLabel;
66+
6067
/**
6168
* Constructor
6269
*
6370
* @param \Magento\Sales\Model\Order\StatusFactory $orderStatusFactory
6471
* @param \Magento\Sales\Model\ResourceModel\Order\Status\CollectionFactory $orderStatusCollectionFactory
6572
* @param \Magento\Framework\App\State $state
73+
* @param StatusLabel|null $statusLabel
6674
*/
6775
public function __construct(
6876
\Magento\Sales\Model\Order\StatusFactory $orderStatusFactory,
6977
\Magento\Sales\Model\ResourceModel\Order\Status\CollectionFactory $orderStatusCollectionFactory,
70-
\Magento\Framework\App\State $state
78+
\Magento\Framework\App\State $state,
79+
StatusLabel $statusLabel = null
7180
) {
7281
$this->orderStatusFactory = $orderStatusFactory;
7382
$this->orderStatusCollectionFactory = $orderStatusCollectionFactory;
7483
$this->state = $state;
84+
$this->statusLabel = $statusLabel ?: ObjectManager::getInstance()->get(StatusLabel::class);
7585
}
7686

7787
/**
@@ -120,36 +130,19 @@ public function getStateDefaultStatus($state): ?string
120130
return $status;
121131
}
122132

123-
/**
124-
* Get status label for a specified area
125-
*
126-
* @param string|null $code
127-
* @param string $area
128-
* @return string|null
129-
*/
130-
private function getStatusLabelForArea(?string $code, string $area): ?string
131-
{
132-
$code = $this->maskStatusForArea($area, $code);
133-
$status = $this->orderStatusFactory->create()->load($code);
134-
135-
if ($area === 'adminhtml') {
136-
return $status->getLabel();
137-
}
138-
139-
return $status->getStoreLabel();
140-
}
141133

142134
/**
143135
* Retrieve status label for detected area
144136
*
145137
* @param string|null $code
146138
* @return string|null
147139
* @throws LocalizedException
140+
* @deprecated Functionality moved to separate class
141+
* @see \Magento\Sales\Model\Order\StatusLabel::getStatusLabel
148142
*/
149143
public function getStatusLabel($code)
150144
{
151-
$area = $this->state->getAreaCode() ?: \Magento\Framework\App\Area::AREA_FRONTEND;
152-
return $this->getStatusLabelForArea($code, $area);
145+
return $this->statusLabel->getStatusLabel($code);
153146
}
154147

155148
/**
@@ -158,10 +151,12 @@ public function getStatusLabel($code)
158151
* @param string|null $code
159152
* @return string|null
160153
* @since 102.0.1
154+
* @deprecated Functionality moved to separate class
155+
* @see \Magento\Sales\Model\Order\StatusLabel::getStatusFrontendLabel
161156
*/
162157
public function getStatusFrontendLabel(?string $code): ?string
163158
{
164-
return $this->getStatusLabelForArea($code, \Magento\Framework\App\Area::AREA_FRONTEND);
159+
return $this->statusLabel->getStatusFrontendLabel($code, Area::AREA_FRONTEND);
165160
}
166161

167162
/**
@@ -170,13 +165,12 @@ public function getStatusFrontendLabel(?string $code): ?string
170165
* @param string $area
171166
* @param string $code
172167
* @return string
168+
* @deprecated Functionality moved to separate class
169+
* @see \Magento\Sales\Model\Order\StatusLabel::maskStatusForArea
173170
*/
174171
protected function maskStatusForArea($area, $code)
175172
{
176-
if (isset($this->maskStatusesMapping[$area][$code])) {
177-
return $this->maskStatusesMapping[$area][$code];
178-
}
179-
return $code;
173+
return $this->statusLabel->maskStatusForArea($area, $code);
180174
}
181175

182176
/**
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Sales\Model\Order;
9+
10+
use Magento\Framework\App\Area;
11+
use Magento\Framework\App\State;
12+
use Magento\Sales\Model\Order\StatusFactory;
13+
14+
/**
15+
* Class StatusLabel is responsible for retrieving order status labels based on store of order
16+
*/
17+
class StatusLabel
18+
{
19+
/**
20+
* @var StatusFactory
21+
*/
22+
private $orderStatusFactory;
23+
24+
/**
25+
* @var State
26+
*/
27+
private $state;
28+
29+
/**
30+
* @var array
31+
*/
32+
private $maskStatusesMapping;
33+
34+
/**
35+
* @param StatusFactory $orderStatusFactory
36+
* @param State $state
37+
* @param array $maskStatusesMapping
38+
*/
39+
public function __construct(
40+
StatusFactory $orderStatusFactory,
41+
State $state,
42+
array $maskStatusesMapping = []
43+
) {
44+
$this->orderStatusFactory = $orderStatusFactory;
45+
$this->state = $state;
46+
$this->maskStatusesMapping = $maskStatusesMapping;
47+
}
48+
49+
/**
50+
* Get status label for a specified area
51+
*
52+
* @param string|null $code
53+
* @param string $area
54+
* @param int|null $storeId
55+
* @return string|null
56+
*/
57+
public function getStatusFrontendLabel(?string $code, string $area, int $storeId = null): ?string
58+
{
59+
$code = $this->maskStatusForArea($area, $code);
60+
$status = $this->orderStatusFactory->create()->load($code);
61+
62+
if ($area === Area::AREA_ADMINHTML) {
63+
return $status->getLabel();
64+
}
65+
66+
return (string) $status->getStoreLabel($storeId);
67+
}
68+
69+
/**
70+
* Mask status for order for specified area
71+
*
72+
* @param string $area
73+
* @param string|null $code
74+
* @return string|null
75+
*/
76+
public function maskStatusForArea(string $area, ?string $code): ?string
77+
{
78+
if (isset($this->maskStatusesMapping[$area][$code])) {
79+
return $this->maskStatusesMapping[$area][$code];
80+
}
81+
return $code;
82+
}
83+
84+
/**
85+
* Retrieve status label for detected area
86+
*
87+
* @param $code
88+
* @return string|null
89+
*/
90+
public function getStatusLabel($code)
91+
{
92+
$area = $this->state->getAreaCode() ?: Area::AREA_FRONTEND;
93+
return $this->getStatusFrontendLabel($code, $area);
94+
}
95+
}

app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,28 @@
1818
use Magento\Store\Model\StoreManagerInterface;
1919
use PHPUnit\Framework\MockObject\MockObject;
2020
use PHPUnit\Framework\TestCase;
21+
use Magento\Sales\Model\Order\StatusLabel;
2122

2223
/**
2324
* Test for Magento\Sales\Model\Order\Config class
2425
*/
2526
class ConfigTest extends TestCase
2627
{
28+
/**
29+
* Pending status stub
30+
*/
31+
const STUB_PENDING_STATUS_CODE = 'pending';
32+
33+
/**
34+
* Store view with id 2
35+
*/
36+
const STUB_STORE_VIEW_WITH_ID_2 = 2;
37+
38+
/**
39+
* Pending label in store view 2
40+
*/
41+
const STUB_STORE_VIEW_LABEL_WITH_ID_2 = 'Pending-2';
42+
2743
/**
2844
* @var Config
2945
*/
@@ -49,6 +65,8 @@ class ConfigTest extends TestCase
4965
*/
5066
protected $storeManagerMock;
5167

68+
protected $statusLabel;
69+
5270
/**
5371
* @return void
5472
*/
@@ -68,12 +86,14 @@ protected function setUp(): void
6886
CollectionFactory::class,
6987
['create']
7088
);
89+
$this->statusLabel = $this->createMock(StatusLabel::class);
7190
$this->salesConfig = $objectManager
7291
->getObject(
7392
Config::class,
7493
[
7594
'orderStatusFactory' => $this->statusFactoryMock,
76-
'orderStatusCollectionFactory' => $this->orderStatusCollectionFactoryMock
95+
'orderStatusCollectionFactory' => $this->orderStatusCollectionFactoryMock,
96+
'statusLabel' => $this->statusLabel
7797
]
7898
);
7999
}
@@ -204,6 +224,7 @@ public function testGetStatuses($state, $joinLabels, $collectionData, $expectedR
204224

205225
$this->statusFactoryMock->method('load')
206226
->willReturn($this->orderStatusModel);
227+
$this->statusLabel->method('getStatusLabel')->willReturn('Pending label');
207228

208229
$storeMock = $this->getMockForAbstractClass(StoreInterface::class);
209230
$storeMock->method('getId')

app/code/Magento/Sales/etc/di.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,4 +1027,14 @@
10271027
<argument name="productAvailabilityChecks" xsi:type="array" />
10281028
</arguments>
10291029
</type>
1030+
<type name="Magento\Sales\Model\Order\StatusLabel">
1031+
<arguments>
1032+
<argument name="maskStatusesMapping" xsi:type="array">
1033+
<item name="frontend" xsi:type="array">
1034+
<item name="fraud" xsi:type="const">Magento\Sales\Model\Order::STATUS_FRAUD</item>
1035+
<item name="payment_review" xsi:type="const">Magento\Sales\Model\Order::STATE_PROCESSING</item>
1036+
</item>
1037+
</argument>
1038+
</arguments>
1039+
</type>
10301040
</config>

dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
namespace Magento\Sales\Model\Order;
88

9+
use Magento\Framework\App\State;
10+
use Magento\Sales\Api\Data\OrderInterfaceFactory;
11+
use Magento\TestFramework\Helper\Bootstrap;
12+
913
/**
1014
* Class ShipmentTest
1115
* @package Magento\Sales\Model\Order
@@ -37,13 +41,31 @@ public function theCorrectLabelIsUsedDependingOnTheAreaProvider()
3741
*/
3842
public function testTheCorrectLabelIsUsedDependingOnTheArea($area, $result)
3943
{
40-
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
41-
$objectManager->get(\Magento\Framework\App\State::class)->setAreaCode($area);
44+
$objectManager = Bootstrap::getObjectManager();
45+
$objectManager->get(State::class)->setAreaCode($area);
4246

4347
/** @var \Magento\Sales\Model\Order $order */
4448
$order = $objectManager->create(\Magento\Sales\Model\Order::class);
4549
$order->loadByIncrementId('100000001');
4650

4751
$this->assertEquals($result, $order->getStatusLabel());
4852
}
53+
54+
/**
55+
* Tests that specified order status frontend label for store should be displayed correctly
56+
*
57+
* @magentoDataFixture Magento/Sales/_files/order_status_with_different_labels.php
58+
*/
59+
public function testTheCorrectLabelIsUsedDependingOnTheStore()
60+
{
61+
$objectManager = Bootstrap::getObjectManager();
62+
$objectManager->get(State::class)->setAreaCode('frontend');
63+
$orderFactory = $objectManager->get(OrderInterfaceFactory::class);
64+
$order = $orderFactory->create()->loadByIncrementId('100000001');
65+
$this->assertEquals('Custom status label', $order->getFrontendStatusLabel());
66+
$order->setStoreId(1);
67+
$order->save();
68+
$this->assertEquals(1, $order->getStoreId());
69+
$this->assertEquals('First store label', $order->getFrontendStatusLabel());
70+
}
4971
}

0 commit comments

Comments
 (0)