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; } }