Skip to content

Commit 7d14004

Browse files
ENGCOM-4781: Fix #14958 - remove sales sequence data on store view delete #22296
- Merge Pull Request #22296 from Bartlomiejsz/magento2:feature/fix_14958_sales_sequence_removal - Merged commits: 1. 8529467 2. 4c4ae53 3. 774d40f 4. 8dab9d7 5. 4385c2f 6. 78bfbc8 7. 3ff5c06 8. 85b0730 9. 309a25f 10. c83a283 11. 328bc51 12. 7c078cf 13. 76b2085 14. 11f013c 15. 68d1bed 16. 48f213d 17. 6458cc8 18. 94b6a17 19. f894321
2 parents cde4f67 + f894321 commit 7d14004

File tree

8 files changed

+359
-29
lines changed

8 files changed

+359
-29
lines changed

app/code/Magento/SalesSequence/Model/ResourceModel/Meta.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object)
132132
|| $object->getData('store_id') === null
133133
|| !$object->getData('sequence_table')
134134
) {
135+
// phpcs:ignore Magento2.Exceptions.DirectThrow
135136
throw new Exception(__('Not enough arguments'));
136137
}
137138

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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\SalesSequence\Model\Sequence;
9+
10+
use Magento\Framework\App\ResourceConnection as AppResource;
11+
use Magento\SalesSequence\Model\MetaFactory;
12+
use Magento\SalesSequence\Model\ResourceModel\Meta as ResourceMetadata;
13+
14+
/**
15+
* Delete Sequence by Store.
16+
*/
17+
class DeleteByStore
18+
{
19+
/**
20+
* @var ResourceMetadata
21+
*/
22+
private $resourceMetadata;
23+
24+
/**
25+
* @var MetaFactory
26+
*/
27+
private $metaFactory;
28+
29+
/**
30+
* @var AppResource
31+
*/
32+
private $appResource;
33+
34+
/**
35+
* @param ResourceMetadata $resourceMetadata
36+
* @param MetaFactory $metaFactory
37+
* @param AppResource $appResource
38+
*/
39+
public function __construct(
40+
ResourceMetadata $resourceMetadata,
41+
MetaFactory $metaFactory,
42+
AppResource $appResource
43+
) {
44+
$this->resourceMetadata = $resourceMetadata;
45+
$this->metaFactory = $metaFactory;
46+
$this->appResource = $appResource;
47+
}
48+
49+
/**
50+
* Deletes all sequence linked entites
51+
*
52+
* @param int $storeId
53+
* @return void
54+
* @throws \Exception
55+
*/
56+
public function execute($storeId): void
57+
{
58+
$metadataIds = $this->getMetadataIdsByStoreId($storeId);
59+
$profileIds = $this->getProfileIdsByMetadataIds($metadataIds);
60+
61+
$this->appResource->getConnection()->delete(
62+
$this->appResource->getTableName('sales_sequence_profile'),
63+
['profile_id IN (?)' => $profileIds]
64+
);
65+
66+
foreach ($metadataIds as $metadataId) {
67+
$metadata = $this->metaFactory->create();
68+
$this->resourceMetadata->load($metadata, $metadataId);
69+
if (!$metadata->getId()) {
70+
continue;
71+
}
72+
73+
$this->appResource->getConnection()->dropTable(
74+
$metadata->getSequenceTable()
75+
);
76+
$this->resourceMetadata->delete($metadata);
77+
}
78+
}
79+
80+
/**
81+
* Retrieves Metadata Ids by store id
82+
*
83+
* @param int $storeId
84+
* @return int[]
85+
*/
86+
private function getMetadataIdsByStoreId($storeId)
87+
{
88+
$connection = $this->appResource->getConnection();
89+
$bind = ['store_id' => $storeId];
90+
$select = $connection->select()->from(
91+
$this->appResource->getTableName('sales_sequence_meta'),
92+
['meta_id']
93+
)->where(
94+
'store_id = :store_id'
95+
);
96+
97+
return $connection->fetchCol($select, $bind);
98+
}
99+
100+
/**
101+
* Retrieves Profile Ids by metadata ids
102+
*
103+
* @param int[] $metadataIds
104+
* @return int[]
105+
*/
106+
private function getProfileIdsByMetadataIds(array $metadataIds)
107+
{
108+
$connection = $this->appResource->getConnection();
109+
$select = $connection->select()
110+
->from(
111+
$this->appResource->getTableName('sales_sequence_profile'),
112+
['profile_id']
113+
)->where('meta_id IN (?)', $metadataIds);
114+
115+
return $connection->fetchCol($select);
116+
}
117+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\SalesSequence\Observer;
9+
10+
use Magento\Framework\Event\ObserverInterface;
11+
use Magento\Framework\Event\Observer as EventObserver;
12+
use Magento\SalesSequence\Model\Sequence\DeleteByStore;
13+
14+
/**
15+
* Observer for Sequence Removal.
16+
*/
17+
class SequenceRemovalObserver implements ObserverInterface
18+
{
19+
/**
20+
* @var DeleteByStore
21+
*/
22+
private $deleteByStore;
23+
24+
/**
25+
* @param DeleteByStore $deleteByStore
26+
*/
27+
public function __construct(
28+
DeleteByStore $deleteByStore
29+
) {
30+
$this->deleteByStore = $deleteByStore;
31+
}
32+
33+
/**
34+
* Deletes all sequence linked entities.
35+
*
36+
* @param EventObserver $observer
37+
* @return $this
38+
* @throws \Magento\Framework\Exception\LocalizedException
39+
*/
40+
public function execute(EventObserver $observer)
41+
{
42+
if ($store = $observer->getData('store')) {
43+
$this->deleteByStore->execute($store->getId());
44+
}
45+
46+
return $this;
47+
}
48+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\SalesSequence\Test\Unit\Model\Sequence;
7+
8+
use Magento\Framework\App\ResourceConnection;
9+
use Magento\Framework\DB\Adapter\AdapterInterface;
10+
use Magento\Framework\DB\Select;
11+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
12+
use Magento\SalesSequence\Model\Meta;
13+
use Magento\SalesSequence\Model\MetaFactory;
14+
use Magento\SalesSequence\Model\ResourceModel\Meta as ResourceMeta;
15+
use Magento\SalesSequence\Model\Sequence\DeleteByStore;
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use PHPUnit\Framework\TestCase;
18+
19+
/**
20+
* Test for \Magento\SalesSequence\Model\Sequence\DeleteByStore class.
21+
*/
22+
class DeleteByStoreTest extends TestCase
23+
{
24+
/**
25+
* @var DeleteByStore
26+
*/
27+
private $deleteByStore;
28+
29+
/**
30+
* @var ResourceMeta | MockObject
31+
*/
32+
private $resourceSequenceMeta;
33+
34+
/**
35+
* @var Meta | MockObject
36+
*/
37+
private $meta;
38+
39+
/**
40+
* @var MetaFactory | MockObject
41+
*/
42+
private $metaFactory;
43+
44+
/**
45+
* @var AdapterInterface | MockObject
46+
*/
47+
private $connectionMock;
48+
49+
/**
50+
* @var ResourceConnection | MockObject
51+
*/
52+
private $resourceMock;
53+
54+
/**
55+
* @var Select | MockObject
56+
*/
57+
private $select;
58+
59+
protected function setUp()
60+
{
61+
$this->connectionMock = $this->getMockForAbstractClass(
62+
AdapterInterface::class,
63+
[],
64+
'',
65+
false,
66+
false,
67+
true,
68+
['delete', 'query']
69+
);
70+
$this->resourceSequenceMeta = $this->createPartialMock(
71+
ResourceMeta::class,
72+
['load', 'delete']
73+
);
74+
$this->meta = $this->createPartialMock(
75+
Meta::class,
76+
['getSequenceTable']
77+
);
78+
$this->resourceMock = $this->createMock(ResourceConnection::class);
79+
$this->select = $this->createMock(Select::class);
80+
$this->metaFactory = $this->createPartialMock(MetaFactory::class, ['create']);
81+
$this->metaFactory->method('create')->willReturn($this->meta);
82+
83+
$helper = new ObjectManager($this);
84+
$this->deleteByStore = $helper->getObject(
85+
DeleteByStore::class,
86+
[
87+
'resourceMetadata' => $this->resourceSequenceMeta,
88+
'metaFactory' => $this->metaFactory,
89+
'appResource' => $this->resourceMock,
90+
]
91+
);
92+
}
93+
94+
/**
95+
* @throws \Exception
96+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
97+
*/
98+
public function testExecute()
99+
{
100+
$profileTableName = 'sales_sequence_profile';
101+
$storeId = 1;
102+
$metadataIds = [1, 2];
103+
$profileIds = [10, 11];
104+
$this->resourceMock->method('getTableName')
105+
->willReturnCallback(
106+
static function ($tableName) {
107+
return $tableName;
108+
}
109+
);
110+
$this->resourceMock->method('getConnection')
111+
->willReturn($this->connectionMock);
112+
$this->connectionMock
113+
->method('select')
114+
->willReturn($this->select);
115+
116+
$this->select->method('from')
117+
->willReturn($this->select);
118+
$this->select->method('where')
119+
->willReturn($this->select);
120+
121+
$this->connectionMock->method('fetchCol')
122+
->willReturnCallback(
123+
static function ($arg, $arg2) use ($metadataIds, $profileIds) {
124+
if (array_key_exists('store', $arg2)) {
125+
return $metadataIds;
126+
}
127+
128+
return $profileIds;
129+
}
130+
);
131+
132+
$this->connectionMock->expects($this->once())
133+
->method('delete')
134+
->with($profileTableName, ['profile_id IN (?)' => $profileIds])
135+
->willReturn(2);
136+
$this->resourceSequenceMeta
137+
->method('load')
138+
->willReturn($this->meta);
139+
$this->connectionMock
140+
->method('dropTable')
141+
->willReturn(true);
142+
$this->resourceSequenceMeta
143+
->method('delete')
144+
->willReturn($this->resourceSequenceMeta);
145+
$this->deleteByStore->execute($storeId);
146+
}
147+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
9+
<event name="store_delete">
10+
<observer name="magento_sequence" instance="Magento\SalesSequence\Observer\SequenceRemovalObserver" />
11+
</event>
12+
</config>

dev/tests/integration/framework/Magento/TestFramework/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ private function copyAppConfigFiles()
558558
}
559559
}
560560
}
561-
561+
562562
/**
563563
* Copies global configuration file from the tests folder (see TESTS_GLOBAL_CONFIG_FILE)
564564
*

dev/tests/integration/testsuite/Magento/Catalog/Model/Product/UrlTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ public function testGetUrlInStore()
5353
* @magentoConfigFixture fixturestore_store web/unsecure/base_url http://sample-second.com/
5454
* @magentoConfigFixture fixturestore_store web/unsecure/base_link_url http://sample-second.com/
5555
* @magentoDataFixture Magento/Catalog/_files/product_simple_multistore.php
56-
* @magentoDbIsolation disabled
5756
* @dataProvider getUrlsWithSecondStoreProvider
57+
* @magentoDbIsolation disabled
5858
* @magentoAppArea adminhtml
5959
*/
6060
public function testGetUrlInStoreWithSecondStore($storeCode, $expectedProductUrl)

0 commit comments

Comments
 (0)