Skip to content

Commit 514c7b9

Browse files
ENGCOM-8815: Customers that have unsubscribed to the newsletter in the time span from when the queue was created and the actual sending of the newsletter still receive newsletters #32186
2 parents 592c792 + 65b6c44 commit 514c7b9

File tree

6 files changed

+157
-14
lines changed

6 files changed

+157
-14
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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\Newsletter\Model\Plugin;
9+
10+
use Magento\Newsletter\Model\RemoveSubscriberFromQueueLink;
11+
use Magento\Newsletter\Model\Subscriber;
12+
13+
/**
14+
* Plugin for removing subscriber from queue after unsubscribe
15+
*/
16+
class RemoveSubscriberFromQueue
17+
{
18+
/**
19+
* @var RemoveSubscriberFromQueueLink
20+
*/
21+
private $removeSubscriberFromQueueLink;
22+
23+
/**
24+
* @param RemoveSubscriberFromQueueLink $removeSubscriberFromQueueLink
25+
*/
26+
public function __construct(RemoveSubscriberFromQueueLink $removeSubscriberFromQueueLink)
27+
{
28+
$this->removeSubscriberFromQueueLink = $removeSubscriberFromQueueLink;
29+
}
30+
31+
/**
32+
* Removes subscriber from queue
33+
*
34+
* @param Subscriber $subject
35+
* @param Subscriber $subscriber
36+
* @return Subscriber
37+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
38+
*/
39+
public function afterUnsubscribe(Subscriber $subject, Subscriber $subscriber): Subscriber
40+
{
41+
if ($subscriber->isStatusChanged() && $subscriber->getSubscriberStatus() === Subscriber::STATUS_UNSUBSCRIBED) {
42+
$this->removeSubscriberFromQueueLink->execute((int) $subscriber->getId());
43+
}
44+
45+
return $subscriber;
46+
}
47+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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\Newsletter\Model;
9+
10+
use Magento\Framework\App\ResourceConnection;
11+
12+
/**
13+
* Responsible for removing subscriber from queue
14+
*/
15+
class RemoveSubscriberFromQueueLink
16+
{
17+
/**
18+
* @var ResourceConnection
19+
*/
20+
private $resourceConnection;
21+
22+
/**
23+
* @param ResourceConnection $resourceConnection
24+
*/
25+
public function __construct(ResourceConnection $resourceConnection)
26+
{
27+
$this->resourceConnection = $resourceConnection;
28+
}
29+
30+
/**
31+
* Removes subscriber from queue
32+
*
33+
* @param int $subscriberId
34+
* @return void
35+
*/
36+
public function execute(int $subscriberId): void
37+
{
38+
$connection = $this->resourceConnection->getConnection();
39+
40+
$connection->delete(
41+
$this->resourceConnection->getTableName('newsletter_queue_link'),
42+
['subscriber_id = ?' => $subscriberId, 'letter_sent_at IS NULL']
43+
);
44+
}
45+
}

app/code/Magento/Newsletter/Model/ResourceModel/Queue.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public function addSubscribersToQueue(ModelQueue $queue, array $subscriberIds)
8686
$usedIds = array_flip($connection->fetchCol($select));
8787
$subscriberIds = array_flip($subscriberIds);
8888
$newIds = array_diff_key($subscriberIds, $usedIds);
89-
89+
9090
$connection->beginTransaction();
9191
try {
9292
foreach (array_keys($newIds) as $subscriberId) {

app/code/Magento/Newsletter/Model/Subscriber.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ public function getStatus()
308308
*/
309309
public function setStatus($value)
310310
{
311+
if ($this->getSubscriberStatus() !== $value) {
312+
$this->setStatusChanged(true);
313+
}
314+
311315
return $this->setSubscriberStatus($value);
312316
}
313317

@@ -449,7 +453,8 @@ public function unsubscribe()
449453
}
450454

451455
if ($this->getSubscriberStatus() != self::STATUS_UNSUBSCRIBED) {
452-
$this->setSubscriberStatus(self::STATUS_UNSUBSCRIBED)->save();
456+
$this->setStatus(self::STATUS_UNSUBSCRIBED);
457+
$this->save();
453458
$this->sendUnsubscriptionEmail();
454459
}
455460
return $this;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
type="Magento\Newsletter\Model\Plugin\CustomerPlugin"/>
2727
</type>
2828
<type name="Magento\Newsletter\Model\Subscriber">
29+
<plugin name="remove_subscriber_from_queue_after_unsubscribe" type="Magento\Newsletter\Model\Plugin\RemoveSubscriberFromQueue"/>
2930
<arguments>
3031
<argument name="customerSession" xsi:type="object">Magento\Customer\Model\Session\Proxy</argument>
3132
</arguments>

dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
namespace Magento\Newsletter\Model;
99

1010
use Magento\Customer\Api\CustomerRepositoryInterface;
11-
use Magento\Framework\Mail\EmailMessage;
1211
use Magento\Framework\Exception\LocalizedException;
1312
use Magento\Framework\Exception\NoSuchEntityException;
14-
use Magento\Framework\ObjectManagerInterface;
13+
use Magento\Framework\Mail\EmailMessage;
14+
use Magento\Newsletter\Model\ResourceModel\Subscriber\CollectionFactory;
1515
use Magento\TestFramework\Helper\Bootstrap;
1616
use Magento\TestFramework\Mail\Template\TransportBuilderMock;
1717
use PHPUnit\Framework\TestCase;
@@ -26,27 +26,42 @@ class SubscriberTest extends TestCase
2626
private const CONFIRMATION_SUBSCRIBE = 'You have been successfully subscribed to our newsletter.';
2727
private const CONFIRMATION_UNSUBSCRIBE = 'You have been unsubscribed from the newsletter.';
2828

29-
/** @var ObjectManagerInterface */
30-
private $objectManager;
31-
32-
/** @var SubscriberFactory */
29+
/**
30+
* @var SubscriberFactory
31+
*/
3332
private $subscriberFactory;
3433

35-
/** @var TransportBuilderMock */
34+
/**
35+
* @var TransportBuilderMock
36+
*/
3637
private $transportBuilder;
3738

38-
/** @var CustomerRepositoryInterface */
39+
/**
40+
* @var CustomerRepositoryInterface
41+
*/
3942
private $customerRepository;
4043

44+
/**
45+
* @var QueueFactory
46+
*/
47+
private $queueFactory;
48+
49+
/**
50+
* @var CollectionFactory
51+
*/
52+
private $subscriberCollectionFactory;
53+
4154
/**
4255
* @inheritdoc
4356
*/
4457
protected function setUp(): void
4558
{
46-
$this->objectManager = Bootstrap::getObjectManager();
47-
$this->subscriberFactory = $this->objectManager->get(SubscriberFactory::class);
48-
$this->transportBuilder = $this->objectManager->get(TransportBuilderMock::class);
49-
$this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class);
59+
$objectManager = Bootstrap::getObjectManager();
60+
$this->subscriberFactory = $objectManager->get(SubscriberFactory::class);
61+
$this->transportBuilder = $objectManager->get(TransportBuilderMock::class);
62+
$this->customerRepository = $objectManager->get(CustomerRepositoryInterface::class);
63+
$this->queueFactory = $objectManager->get(QueueFactory::class);
64+
$this->subscriberCollectionFactory = $objectManager->get(CollectionFactory::class);
5065
}
5166

5267
/**
@@ -157,6 +172,36 @@ public function testConfirm(): void
157172
);
158173
}
159174

175+
/**
176+
* Unsubscribe and check queue
177+
*
178+
* @magentoDataFixture Magento/Newsletter/_files/queue.php
179+
*
180+
* @return void
181+
*/
182+
public function testUnsubscribeCustomer(): void
183+
{
184+
$firstSubscriber = $this->subscriberFactory->create()
185+
->load('[email protected]', 'subscriber_email');
186+
$secondSubscriber = $this->subscriberFactory->create()
187+
->load('[email protected]', 'subscriber_email');
188+
189+
$queue = $this->queueFactory->create()
190+
->load('CustomerSupport', 'newsletter_sender_name');
191+
$queue->addSubscribersToQueue([$firstSubscriber->getId(), $secondSubscriber->getId()]);
192+
193+
$secondSubscriber->unsubscribe();
194+
195+
$collection = $this->subscriberCollectionFactory->create()
196+
->useQueue($queue);
197+
198+
$this->assertCount(1, $collection);
199+
$this->assertEquals(
200+
201+
$collection->getFirstItem()->getData('subscriber_email')
202+
);
203+
}
204+
160205
/**
161206
* @magentoDataFixture Magento/Customer/_files/customer_confirmation_config_enable.php
162207
* @magentoDataFixture Magento/Newsletter/_files/newsletter_unconfirmed_customer.php

0 commit comments

Comments
 (0)