Files
piratepoet/mailpoet/tests/integration/Segments/WooCommerceTest.php
Brezo Cordero b7a37e69b7 Init $customerRoleAdded on WooCommerceTest.php
This will make it non-nullable and have only the type bool.

[MAILPOET-3720]
2022-05-23 12:04:12 +02:00

922 lines
38 KiB
PHP

<?php declare(strict_types = 1);
namespace MailPoet\Test\Segments;
require_once(ABSPATH . 'wp-admin/includes/user.php');
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Segments\SegmentsRepository;
use MailPoet\Segments\WooCommerce as WooCommerceSegment;
use MailPoet\Segments\WP;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscribers\Source;
use MailPoet\Subscribers\SubscriberSaveController;
use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\WooCommerce\Helper;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon;
use PHPUnit\Framework\MockObject\MockObject;
require_once('WPTestUser.php');
class WooCommerceTest extends \MailPoetTest {
/** @var bool */
public $customerRoleAdded = false;
/** @var string[] */
private $userEmails = [];
/** @var WooCommerceSegment */
private $wooCommerce;
/** @var SettingsController */
private $settings;
/** @var SubscribersRepository */
private $subscribersRepository;
/** @var SegmentsRepository */
private $segmentsRepository;
/** @var SubscriberSegmentRepository */
private $subscriberSegmentsRepository;
public function _before(): void {
$this->subscribersRepository = $this->diContainer->get(SubscribersRepository::class);
$this->segmentsRepository = $this->diContainer->get(SegmentsRepository::class);
$this->subscriberSegmentsRepository = $this->diContainer->get(SubscriberSegmentRepository::class);
$this->wooCommerce = $this->getWooCommerce();
$this->settings = $this->diContainer->get(SettingsController::class);
$this->cleanData();
$this->addCustomerRole();
}
public function testItSynchronizesNewRegisteredCustomer(): void {
$firstName = 'Test First';
$lastName = 'Test Last';
$user = $this->insertRegisteredCustomerWithOrder(null, ['first_name' => $firstName, 'last_name' => $lastName]);
$this->createSubscriber(
'Mike',
'Mike',
$user->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_SUBSCRIBED,
$user->ID,
Source::WORDPRESS_USER
);
$hook = 'woocommerce_new_customer';
$this->wooCommerce->synchronizeRegisteredCustomer($user->ID, $hook);
$subscriber = $this->findWCSubscriberByWpUserId($user->ID);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber)->notEmpty();
expect($subscriber->getEmail())->equals($user->user_email); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($subscriber->getFirstName())->equals($firstName);
expect($subscriber->getLastName())->equals($lastName);
expect($subscriber->getIsWoocommerceUser())->equals(true);
expect($subscriber->getSource())->equals(Source::WOOCOMMERCE_USER);
expect($subscriber->getDeletedAt())->equals(null);
}
public function testItSynchronizesUpdatedRegisteredCustomer(): void {
$firstName = 'Test First';
$lastName = 'Test Last';
$user = $this->insertRegisteredCustomerWithOrder(null, ['first_name' => $firstName, 'last_name' => $lastName]);
$this->createSubscriber(
'Mike',
'Mike',
$user->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_UNSUBSCRIBED,
$user->ID,
Source::WORDPRESS_USER
);
$hook = 'woocommerce_update_customer';
$this->wooCommerce->synchronizeRegisteredCustomer($user->ID, $hook);
$subscriber = $this->findWCSubscriberByWpUserId($user->ID);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber)->notEmpty();
expect($subscriber->getEmail())->equals($user->user_email); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($subscriber->getFirstName())->equals($firstName);
expect($subscriber->getLastName())->equals($lastName);
expect($subscriber->getIsWoocommerceUser())->equals(true);
expect($subscriber->getSource())->equals(Source::WORDPRESS_USER); // no overriding
expect($subscriber->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED); // no overriding
}
public function testItSynchronizesDeletedRegisteredCustomer(): void {
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
$user = $this->insertRegisteredCustomer();
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
$user->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_UNSUBSCRIBED,
$user->ID,
Source::WORDPRESS_USER
);
$association = $this->createSubscriberSegment($subscriber, $wooCommerceSegment);
expect($this->subscriberSegmentsRepository->findOneById($association->getId()))->notEmpty();
$hook = 'woocommerce_delete_customer';
$this->wooCommerce->synchronizeRegisteredCustomer($user->ID, $hook);
expect($this->subscriberSegmentsRepository->findOneById($association->getId()))->notEmpty();
}
public function testItSynchronizesNewGuestCustomer(): void {
$this->settings->set('signup_confirmation', ['enabled' => true]);
$this->settings->set('woocommerce.optin_on_checkout', ['enabled' => false]);
$guest = $this->insertGuestCustomer();
$woocommerceSegment = $this->getWooCommerceSegmentForGuestUser($guest);
$woocommerceSegment->synchronizeGuestCustomer($guest['order_id']);
$subscribers = $this->getWCSubscribersByEmails([$guest['email']]);
expect($subscribers)->isEmpty();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $guest['email']]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getFirstName())->equals($guest['first_name']);
expect($subscriber->getLastName())->equals($guest['last_name']);
expect($subscriber->getIsWoocommerceUser())->equals(true);
expect($subscriber->getSource())->equals(Source::WOOCOMMERCE_USER);
}
public function testItSynchronizesNewGuestCustomerWithDoubleOptinDisabled(): void {
$this->settings->set('signup_confirmation', ['enabled' => false]);
$this->settings->set('woocommerce.optin_on_checkout', ['enabled' => false]);
$this->settings->resetCache();
$guest = $this->insertGuestCustomer();
$woocommerceSegment = $this->getWooCommerceSegmentForGuestUser($guest);
$woocommerceSegment->synchronizeGuestCustomer($guest['order_id']);
$subscribers = $this->getWCSubscribersByEmails([$guest['email']]);
expect($subscribers)->isEmpty();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $guest['email']]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getFirstName())->equals($guest['first_name']);
expect($subscriber->getLastName())->equals($guest['last_name']);
expect($subscriber->getIsWoocommerceUser())->equals(true);
expect($subscriber->getSource())->equals(Source::WOOCOMMERCE_USER);
}
public function testItSynchronizesNewGuestCustomerWithOptinCheckoutEnabled(): void {
$this->settings->set('signup_confirmation', ['enabled' => false]);
$this->settings->set('woocommerce.optin_on_checkout', ['enabled' => true]);
$this->settings->resetCache();
$guest = $this->insertGuestCustomer();
$woocommerceSegment = $this->getWooCommerceSegmentForGuestUser($guest);
$woocommerceSegment->synchronizeGuestCustomer($guest['order_id']);
$subscribers = $this->getWCSubscribersByEmails([$guest['email']]);
expect($subscribers)->isEmpty();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $guest['email']]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getFirstName())->equals($guest['first_name']);
expect($subscriber->getLastName())->equals($guest['last_name']);
expect($subscriber->getIsWoocommerceUser())->equals(true);
expect($subscriber->getSource())->equals(Source::WOOCOMMERCE_USER);
}
public function testItSynchronizesCustomers(): void {
$this->settings->set('signup_confirmation', ['enabled' => true]);
$this->settings->set('mailpoet_subscribe_old_woocommerce_customers', ['dummy' => '1', 'enabled' => '1']);
$user = $this->insertRegisteredCustomer();
$guest = $this->insertGuestCustomer();
$this->wooCommerce->synchronizeCustomers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(2);
$subscriber = $this->subscribersRepository->findOneBy(['email' => $user->user_email]); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getStatus())->equals(SubscriberEntity::STATUS_UNCONFIRMED);
expect($subscriber->getSource())->equals(Source::WOOCOMMERCE_USER);
$subscriber = $this->subscribersRepository->findOneBy(['email' => $guest['email']]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
expect($subscriber->getSource())->equals(Source::WOOCOMMERCE_USER);
}
public function testItSynchronizesCustomersInBatches(): void {
$user1 = $this->insertGuestCustomer();
$user2 = $this->insertGuestCustomer();
$user3 = $this->insertGuestCustomer();
$orderIds = [
$user1['order_id'],
$user2['order_id'],
$user3['order_id'],
];
$lowestOrderId = min($orderIds);
$highestOrderId = max($orderIds);
// Check if empty batch run returns the highest order ID to an avoid infinite loop
$lastOrderId = $this->wooCommerce->synchronizeCustomers($lowestOrderId - 2, $highestOrderId, 1);
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(0);
// Check regular subscriber sync
$lastOrderId = $this->wooCommerce->synchronizeCustomers($lastOrderId, $highestOrderId, 1);
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(1);
$lastOrderId = $this->wooCommerce->synchronizeCustomers($lastOrderId, $highestOrderId, 1);
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(2);
$this->wooCommerce->synchronizeCustomers($lastOrderId, $highestOrderId, 1);
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(3);
}
public function testItSynchronizesNewCustomers(): void {
$this->insertRegisteredCustomer();
$this->insertGuestCustomer();
$this->wooCommerce->synchronizeCustomers();
$this->insertRegisteredCustomer();
$this->insertGuestCustomer();
$this->wooCommerce->synchronizeCustomers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(4);
}
public function testItSynchronizesPresubscribedRegisteredCustomers(): void {
$randomNumber = 12345;
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
'user-sync-test' . $randomNumber . '@example.com',
SubscriberEntity::STATUS_UNSUBSCRIBED,
null
);
$user = $this->insertRegisteredCustomer($randomNumber);
$this->wooCommerce->synchronizeCustomers();
$wpSubscriber = $this->subscribersRepository->findOneBy([
'wpUserId' => $user->ID,
'isWoocommerceUser' => true,
]);
assert($wpSubscriber instanceof SubscriberEntity);
expect($wpSubscriber)->notEmpty();
expect($wpSubscriber->getId())->equals($subscriber->getId());
expect($wpSubscriber->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
}
public function testItSynchronizesPresubscribedGuestCustomers(): void {
$randomNumber = 12345;
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
'user-sync-test' . $randomNumber . '@example.com',
SubscriberEntity::STATUS_UNSUBSCRIBED,
null
);
$guest = $this->insertGuestCustomer($randomNumber);
$this->wooCommerce->synchronizeCustomers();
$wpSubscriber = $this->subscribersRepository->findOneBy([
'email' => $guest['email'],
'isWoocommerceUser' => true,
]);
assert($wpSubscriber instanceof SubscriberEntity);
expect($wpSubscriber)->notEmpty();
expect($wpSubscriber->getEmail())->equals($subscriber->getEmail());
expect($wpSubscriber->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
}
public function testItDoesNotSynchronizeEmptyEmailsForNewUsers(): void {
$guest = $this->insertGuestCustomer();
update_post_meta($guest['order_id'], '_billing_email', '');
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy(['email' => '']);
expect($subscriber)->isEmpty();
$this->deleteOrder($guest['order_id']);
}
public function testItDoesNotSynchronizeInvalidEmailsForNewUsers(): void {
$guest = $this->insertGuestCustomer();
$invalidEmail = 'ivalid.@email.com';
update_post_meta($guest['order_id'], '_billing_email', $invalidEmail);
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $invalidEmail]);
expect($subscriber)->isEmpty();
$this->deleteOrder($guest['order_id']);
}
public function testItSynchronizesFirstNamesForRegisteredCustomers(): void {
$user = $this->insertRegisteredCustomerWithOrder(null, ['first_name' => '']);
$this->wooCommerce->synchronizeCustomers();
update_post_meta($user->orderId, '_billing_first_name', 'First name');
$this->createOrder(['email' => $user->user_email, 'first_name' => 'First name (newer)']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy(['wpUserId' => $user->ID]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getFirstName())->equals('First name (newer)');
}
public function testItSynchronizesLastNamesForRegisteredCustomers(): void {
$user = $this->insertRegisteredCustomerWithOrder(null, ['last_name' => '']);
$this->wooCommerce->synchronizeCustomers();
update_post_meta($user->orderId, '_billing_last_name', 'Last name');
$this->createOrder(['email' => $user->user_email, 'last_name' => 'Last name (newer)']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy(['wpUserId' => $user->ID]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getLastName())->equals('Last name (newer)');
}
public function testItSynchronizesFirstNamesForGuestCustomers(): void {
$guest = $this->insertGuestCustomer(null, ['first_name' => '']);
$this->wooCommerce->synchronizeCustomers();
update_post_meta($guest['order_id'], '_billing_first_name', 'First name');
$this->createOrder(['email' => $guest['email'], 'first_name' => 'First name (newer)']);
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $guest['email']]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getFirstName())->equals('First name (newer)');
}
public function testItSynchronizesLastNamesForGuestCustomers(): void {
$guest = $this->insertGuestCustomer(null, ['last_name' => '']);
$this->wooCommerce->synchronizeCustomers();
update_post_meta($guest['order_id'], '_billing_last_name', 'Last name');
$this->createOrder(['email' => $guest['email'], 'last_name' => 'Last name (newer)']);
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $guest['email']]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getLastName())->equals('Last name (newer)');
}
public function testItSynchronizesSegment(): void {
$this->insertRegisteredCustomer();
$this->insertRegisteredCustomer();
$this->insertGuestCustomer();
$this->insertGuestCustomer();
$this->wooCommerce->synchronizeCustomers();
$subscribers = $this->getWCSubscribersByEmails($this->userEmails);
expect($subscribers)->count(4);
}
public function testItDoesntRemoveRegisteredCustomersFromTrash(): void {
$user = $this->insertRegisteredCustomer();
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy([
'email' => $user->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
'isWoocommerceUser' => true,
]);
assert($subscriber instanceof SubscriberEntity);
$subscriber->setDeletedAt(Carbon::now());
$this->subscribersRepository->flush();
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy([
'email' => $user->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
'isWoocommerceUser' => true,
]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getDeletedAt())->notNull();
}
public function testItDoesntRemoveGuestCustomersFromTrash(): void {
$guest = $this->insertGuestCustomer();
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy([
'email' => $guest['email'],
'isWoocommerceUser' => true,
]);
assert($subscriber instanceof SubscriberEntity);
$subscriber->setDeletedAt(Carbon::now());
$this->entityManager->flush();
$this->wooCommerce->synchronizeCustomers();
$subscriber = $this->subscribersRepository->findOneBy([
'email' => $guest['email'],
'isWoocommerceUser' => true,
]);
assert($subscriber instanceof SubscriberEntity);
expect($subscriber->getDeletedAt())->notNull();
}
public function testItRemovesOrphanedSubscribers(): void {
$this->insertRegisteredCustomer();
$this->insertGuestCustomer();
$user = $this->insertRegisteredCustomerWithOrder();
$guest = $this->insertGuestCustomer();
$this->wooCommerce->synchronizeCustomers();
$user->remove_role('customer');
$this->deleteOrder($user->orderId);
$this->deleteOrder($guest['order_id']);
$this->wooCommerce->synchronizeCustomers();
$subscribers = $this->getWCSubscribersByEmails($this->userEmails);
expect($subscribers)->count(2);
}
public function testItDoesntDeleteNonWCData(): void {
$this->insertRegisteredCustomer();
$this->insertGuestCustomer();
// WP user
$user = $this->insertRegisteredCustomer();
$user->remove_role('customer');
$this->createSubscriber(
'John',
'John',
$user->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_UNCONFIRMED,
$user->ID
);
// Regular subscriber
$this->createSubscriber(
'Mike',
'Mike',
'user-sync-test2' . rand() . '@example.com',
SubscriberEntity::STATUS_SUBSCRIBED
);
// email is empty
$subscriber3 = $this->createSubscriber(
'Dave',
'Dave',
'user-sync-test3' . rand() . '@example.com',
SubscriberEntity::STATUS_SUBSCRIBED
);
$this->clearEmail($subscriber3);
$this->wooCommerce->synchronizeCustomers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(4);
$this->entityManager->clear();
$dbSubscriber = $this->subscribersRepository->findOneById($subscriber3->getId());
assert($dbSubscriber instanceof SubscriberEntity);
expect($dbSubscriber)->notEmpty();
$this->entityManager->remove($dbSubscriber);
$this->entityManager->flush();
}
public function testItUnsubscribesSubscribersWithoutWCFlagFromWCSegment(): void {
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
'user-sync-test' . rand() . '@example.com',
SubscriberEntity::STATUS_SUBSCRIBED
);
$association = $this->createSubscriberSegment($subscriber, $wooCommerceSegment);
expect($this->subscriberSegmentsRepository->findOneById($association->getId()))->notEmpty();
$this->wooCommerce->synchronizeCustomers();
$this->entityManager->clear();
expect($this->subscriberSegmentsRepository->findOneById($association->getId()))->isEmpty();
}
public function testItUnsubscribesSubscribersWithoutEmailFromWCSegment(): void {
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
'user-sync-test' . rand() . '@example.com', // need to pass validation
SubscriberEntity::STATUS_SUBSCRIBED
);
$subscriber->setIsWoocommerceUser(true);
$this->subscribersRepository->flush();
$this->clearEmail($subscriber);
$association = $this->createSubscriberSegment($subscriber, $wooCommerceSegment);
expect($this->subscriberSegmentsRepository->findOneById($association->getId()))->notEmpty();
$this->entityManager->clear();
$this->wooCommerce->synchronizeCustomers();
expect($this->subscriberSegmentsRepository->findOneById($association->getId()))->isEmpty();
}
public function testItSetGlobalStatusUnsubscribedForUsersUnsyncedFromWooCommerceSegment(): void {
$guest = $this->insertGuestCustomer();
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
$guest['email'],
SubscriberEntity::STATUS_SUBSCRIBED
);
$subscriber->setIsWoocommerceUser(true);
$subscriber->setConfirmedIp('123');
$this->subscribersRepository->flush();
$this->createSubscriberSegment($subscriber, $wooCommerceSegment, SubscriberEntity::STATUS_UNSUBSCRIBED);
$this->wooCommerce->synchronizeCustomers();
$this->entityManager->clear();
$subscriberAfterUpdate = $this->subscribersRepository->findOneBy(['email' => $subscriber->getEmail()]);
assert($subscriberAfterUpdate instanceof SubscriberEntity);
expect($subscriberAfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
}
public function testItDoesntSetGlobalStatusUnsubscribedIfUserHasMoreLists(): void {
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
$guest = $this->insertGuestCustomer();
$subscriber = $this->createSubscriber(
'Mike',
'Mike',
$guest['email'],
SubscriberEntity::STATUS_SUBSCRIBED
);
$subscriber->setIsWoocommerceUser(true);
$subscriber->setConfirmedIp('123');
$this->subscribersRepository->flush();
$this->createSubscriberSegment(
$subscriber,
$wooCommerceSegment,
SubscriberEntity::STATUS_UNSUBSCRIBED
);
$segment = $this->createSegment();
$this->createSubscriberSegment(
$subscriber,
$segment
);
$this->wooCommerce->synchronizeCustomers();
$this->entityManager->clear();
$subscriberAfterUpdate = $this->subscribersRepository->findOneBy(['email' => $subscriber->getEmail()]);
assert($subscriberAfterUpdate instanceof SubscriberEntity);
expect($subscriberAfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
}
public function testItSubscribesSubscribersToWCListWhenSettingIsEnabled(): void {
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
$user1 = $this->insertRegisteredCustomer();
$user2 = $this->insertRegisteredCustomer();
$subscriber1 = $this->createSubscriber(
'Mike',
'Mike',
$user1->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_UNSUBSCRIBED
);
$subscriber1->setIsWoocommerceUser(true);
$this->subscribersRepository->flush();
$association1 = $this->createSubscriberSegment($subscriber1, $wooCommerceSegment, SubscriberEntity::STATUS_UNSUBSCRIBED);
$subscriber2 = $this->createSubscriber(
'Mike',
'Mike',
$user2->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_UNSUBSCRIBED
);
$subscriber2->setIsWoocommerceUser(true);
$subscriber2->setConfirmedIp('123');
$this->subscribersRepository->flush();
$association2 = $this->createSubscriberSegment($subscriber2, $wooCommerceSegment, SubscriberEntity::STATUS_UNSUBSCRIBED);
$this->settings->set('mailpoet_subscribe_old_woocommerce_customers', ['dummy' => '1', 'enabled' => '1']);
$this->wooCommerce->synchronizeCustomers();
$this->entityManager->clear();
$subscriber1AfterUpdate = $this->subscribersRepository->findOneBy(['email' => $subscriber1->getEmail()]);
$subscriber2AfterUpdate = $this->subscribersRepository->findOneBy(['email' => $subscriber2->getEmail()]);
assert($subscriber1AfterUpdate instanceof SubscriberEntity);
assert($subscriber2AfterUpdate instanceof SubscriberEntity);
expect($subscriber1AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
expect($subscriber2AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
$association1AfterUpdate = $this->subscriberSegmentsRepository->findOneById($association1->getId());
$association2AfterUpdate = $this->subscriberSegmentsRepository->findOneById($association2->getId());
assert($association1AfterUpdate instanceof SubscriberSegmentEntity);
assert($association2AfterUpdate instanceof SubscriberSegmentEntity);
expect($association1AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
expect($association2AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
}
public function testItUnsubscribesSubscribersFromWCListWhenSettingIsDisabled(): void {
$wcSegment = $this->segmentsRepository->getWooCommerceSegment();
$user1 = $this->insertRegisteredCustomer();
$user2 = $this->insertRegisteredCustomer();
$subscriber1 = $this->createSubscriber(
'Mike',
'Mike',
$user1->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_SUBSCRIBED
);
$subscriber1->setIsWoocommerceUser(true);
$this->subscribersRepository->flush();
$association1 = $this->createSubscriberSegment($subscriber1, $wcSegment);
$subscriber2 = $this->createSubscriber(
'Mike',
'Mike',
$user2->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
SubscriberEntity::STATUS_SUBSCRIBED
);
$subscriber2->setIsWoocommerceUser(true);
$subscriber2->setConfirmedIp('123');
$this->subscribersRepository->flush();
$association2 = $this->createSubscriberSegment($subscriber2, $wcSegment);
$this->settings->set('mailpoet_subscribe_old_woocommerce_customers', ['dummy' => '1']);
$this->wooCommerce->synchronizeCustomers();
$this->entityManager->clear();
$subscriber1AfterUpdate = $this->subscribersRepository->findOneBy(['email' => $subscriber1->getEmail()]);
$subscriber2AfterUpdate = $this->subscribersRepository->findOneBy(['email' => $subscriber2->getEmail()]);
assert($subscriber1AfterUpdate instanceof SubscriberEntity);
assert($subscriber2AfterUpdate instanceof SubscriberEntity);
expect($subscriber1AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
expect($subscriber2AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
$association1AfterUpdate = $this->subscriberSegmentsRepository->findOneById($association1->getId());
$association2AfterUpdate = $this->subscriberSegmentsRepository->findOneById($association2->getId());
assert($association1AfterUpdate instanceof SubscriberSegmentEntity);
assert($association2AfterUpdate instanceof SubscriberSegmentEntity);
expect($association1AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
expect($association2AfterUpdate->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
}
public function _after(): void {
$this->cleanData();
$this->removeCustomerRole();
}
private function addCustomerRole(): void {
if (!get_role('customer')) {
add_role('customer', 'Customer');
$this->customerRoleAdded = true;
}
}
private function removeCustomerRole(): void {
if ($this->customerRoleAdded) {
remove_role('customer');
}
}
private function cleanData(): void {
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
$segmentsTable = $this->entityManager->getClassMetadata(SegmentEntity::class)->getTableName();
$subscriberSegmentTable = $this->entityManager->getClassMetadata(SubscriberSegmentEntity::class)->getTableName();
$connection = $this->entityManager->getConnection();
$connection->executeQuery('TRUNCATE ' . $segmentsTable);
$connection->executeQuery('TRUNCATE ' . $subscriberSegmentTable);
global $wpdb;
$connection->executeQuery("
DELETE FROM
{$subscriberSegmentTable}
WHERE
subscriber_id IN (SELECT id FROM {$subscribersTable} WHERE email LIKE 'user-sync-test%')
");
$connection->executeQuery("
DELETE FROM
{$wpdb->usermeta}
WHERE
user_id IN (select id from {$wpdb->users} WHERE user_email LIKE 'user-sync-test%')
");
$connection->executeQuery("
DELETE FROM
{$wpdb->users}
WHERE
user_email LIKE 'user-sync-test%'
OR user_login LIKE 'user-sync-test%'
");
$connection->executeQuery("
DELETE FROM
{$subscribersTable}
WHERE
email LIKE 'user-sync-test%'
");
// delete orders
$connection->executeQuery("
DELETE FROM
{$wpdb->posts}
WHERE
id IN (SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_value LIKE 'user-sync-test%')
");
// delete order meta
$connection->executeQuery("
DELETE FROM
{$wpdb->postmeta}
WHERE
post_id IN (
SELECT post_id FROM (
SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_value LIKE 'user-sync-test%'
) AS t
)
");
}
private function getSubscribersCount(): int {
return (int)$this->entityManager->createQueryBuilder()
->select('COUNT(s.id)')
->from(SubscriberEntity::class, 's')
->where('s.email LIKE :prefix')
->setParameter('prefix', 'user-sync-test%')
->getQuery()
->getSingleScalarResult();
}
/**
* Insert a user without invoking wp hooks.
* Those tests are testing user synchronisation, so we need data in wp_users table which has not been synchronised to
* mailpoet database yet. We cannot use wp_insert_user functions because they would do the sync on insert.
*
* @return WPTestUser
*/
private function insertRegisteredCustomer(?int $number = null, ?string $firstName = null, ?string $lastName = null): WPTestUser {
global $wpdb;
$connection = $this->entityManager->getConnection();
$numberSql = !is_null($number) ? (int)$number : mt_rand();
// add user
$connection->executeQuery("
INSERT INTO {$wpdb->users} (user_login, user_email, user_registered)
VALUES (
CONCAT('user-sync-test', :number),
CONCAT('user-sync-test', :number, '@example.com'),
'2017-01-02 12:31:12'
)", ['number' => $numberSql]);
$id = $connection->lastInsertId();
if (!is_string($id)) {
throw new \RuntimeException('Unexpected error when creating WP user.');
}
if ($firstName) {
// add user first name
$connection->executeQuery("
INSERT INTO {$wpdb->usermeta} (user_id, meta_key, meta_value)
VALUES (
:id,
'first_name',
:firstName
)
", ['id' => $id, 'firstName' => $firstName]);
}
if ($lastName) {
// add user first name
$connection->executeQuery("
INSERT INTO {$wpdb->usermeta} (user_id, meta_key, meta_value)
VALUES (
:id,
'last_name',
:lastName
)
", ['id' => $id, 'lastName' => $lastName]);
}
// add customer role
$user = new WPTestUser($id);
$user->add_role('customer');
$this->userEmails[] = $user->user_email; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return $user;
}
/**
* A guest customer is whose data is only contained in an order
*/
private function insertGuestCustomer(?int $number = null, ?array $data = null): array {
$number = !is_null($number) ? (int)$number : mt_rand();
// add order
$guest = [
'email' => isset($data['email']) ? $data['email'] : 'user-sync-test' . $number . '@example.com',
'first_name' => isset($data['first_name']) ? $data['first_name'] : 'user-sync-test' . $number . ' first',
'last_name' => isset($data['last_name']) ? $data['last_name'] : 'user-sync-test' . $number . ' last',
];
$guest['order_id'] = $this->createOrder($guest);
$this->userEmails[] = $guest['email'];
return $guest;
}
private function insertRegisteredCustomerWithOrder(?int $number = null, array $data = null): WPTestUser {
$number = !is_null($number) ? (int)$number : mt_rand();
$data = is_array($data) ? $data : [];
$user = $this->insertRegisteredCustomer($number, $data['first_name'] ?? null, $data['last_name'] ?? null);
$data['email'] = $user->user_email; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$data['user_id'] = $user->ID;
$user->orderId = $this->createOrder($data);
return $user;
}
/**
* @param array $data
* @return int
*/
private function createOrder(array $data): int {
$orderData = [
'post_type' => 'shop_order',
'meta_input' => [
'_billing_email' => isset($data['email']) ? $data['email'] : '',
'_billing_first_name' => isset($data['first_name']) ? $data['first_name'] : '',
'_billing_last_name' => isset($data['last_name']) ? $data['last_name'] : '',
],
];
if (!empty($data['user_id'])) {
$orderData['meta_input']['_customer_user'] = (int)$data['user_id'];
}
$id = wp_insert_post($orderData);
$this->assertIsInt($id);
return $id;
}
private function deleteOrder(int $id): void {
global $wpdb;
$connection = $this->entityManager->getConnection();
$connection->executeQuery("
DELETE FROM
{$wpdb->posts}
WHERE
id = :id
", ['id' => $id]);
$connection->executeQuery("
DELETE FROM
{$wpdb->postmeta}
WHERE
post_id = :id
", ['id' => $id]);
}
private function clearEmail(SubscriberEntity $subscriber): void {
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
$this->entityManager->getConnection()->executeQuery('
UPDATE ' . $subscribersTable . '
SET `email` = "" WHERE `id` = ' . $subscriber->getId()
);
}
private function getWooCommerce(?MockObject $wooHelperMock = null): WooCommerceSegment {
if ($wooHelperMock) {
$this->assertInstanceOf(Helper::class, $wooHelperMock);
}
return new WooCommerceSegment(
$this->diContainer->get(SettingsController::class),
$this->diContainer->get(WPFunctions::class),
$wooHelperMock ?? $this->diContainer->get(Helper::class),
$this->diContainer->get(SubscribersRepository::class),
$this->diContainer->get(SegmentsRepository::class),
$this->diContainer->get(SubscriberSegmentRepository::class),
$this->diContainer->get(SubscriberSaveController::class),
$this->diContainer->get(WP::class),
$this->entityManager,
$this->entityManager->getConnection()
);
}
private function getWooCommerceSegmentForGuestUser(array $guest): WooCommerceSegment {
$wcOrderMock = $this->createMock(\WC_Order::class);
$wcOrderMock->method('get_billing_first_name')
->willReturn($guest['first_name']);
$wcOrderMock->method('get_billing_last_name')
->willReturn($guest['last_name']);
$wcHelperMock = $this->createMock(Helper::class);
$wcHelperMock->method('wcGetOrder')
->willReturn($wcOrderMock);
return $this->getWooCommerce($wcHelperMock);
}
private function createSubscriber(
string $firstName,
string $lastName,
string $email,
string $status,
?int $wpUserId = null,
?string $source = null
): SubscriberEntity {
$subscriber = new SubscriberEntity();
$subscriber->setLastName($lastName);
$subscriber->setFirstName($firstName);
if ($wpUserId) $subscriber->setWpUserId($wpUserId);
$subscriber->setEmail($email);
$subscriber->setStatus($status);
if ($source) $subscriber->setSource($source);
$this->entityManager->persist($subscriber);
$this->entityManager->flush();
return $subscriber;
}
private function createSegment(): SegmentEntity {
$segment = new SegmentEntity('Segment', SegmentEntity::TYPE_DEFAULT, '');
$this->segmentsRepository->persist($segment);
$this->segmentsRepository->flush();
return $segment;
}
private function createSubscriberSegment(
SubscriberEntity $subscriber,
SegmentEntity $segment,
string $status = SubscriberEntity::STATUS_SUBSCRIBED
): SubscriberSegmentEntity {
$subscriberSegment = new SubscriberSegmentEntity($segment, $subscriber, $status);
$this->entityManager->persist($subscriberSegment);
$this->entityManager->flush();
return $subscriberSegment;
}
private function findWCSubscriberByWpUserId(int $wpUserId): ?SubscriberEntity {
$subscriber = $this->subscribersRepository->findOneBy(['wpUserId' => $wpUserId]);
assert($subscriber instanceof SubscriberEntity);
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
foreach ($subscriber->getSegments() as $segment) {
if ($segment->getId() === $wooCommerceSegment->getId()) {
return $subscriber;
}
}
return null;
}
/**
* @param string[] $emails
* @return array
*/
private function getWCSubscribersByEmails(array $emails): array {
$subscribers = $this->entityManager->createQueryBuilder()
->select('s')
->from(SubscriberEntity::class, 's')
->where('s.email IN (:emails)')
->andWhere('s.isWoocommerceUser = true')
->setParameter('emails', $emails)
->getQuery()
->getResult();
$result = [];
$wooCommerceSegment = $this->segmentsRepository->getWooCommerceSegment();
foreach ($subscribers as $subscriber) {
foreach ($subscriber->getSegments() as $segment) {
if ($segment->getId() === $wooCommerceSegment->getId()) {
$result[] = $subscriber;
}
}
}
return $result;
}
}