diff --git a/mailpoet/lib/Analytics/Reporter.php b/mailpoet/lib/Analytics/Reporter.php index 6fdc65caeb..5388736123 100644 --- a/mailpoet/lib/Analytics/Reporter.php +++ b/mailpoet/lib/Analytics/Reporter.php @@ -8,6 +8,7 @@ use MailPoet\Automation\Engine\Storage\AutomationStorage; use MailPoet\Config\ServicesChecker; use MailPoet\Cron\CronTrigger; use MailPoet\Entities\DynamicSegmentFilterData; +use MailPoet\Entities\NewsletterEntity; use MailPoet\Listing\ListingDefinition; use MailPoet\Newsletter\NewslettersRepository; use MailPoet\Segments\DynamicSegments\DynamicSegmentFilterRepository; @@ -52,6 +53,7 @@ use MailPoet\Subscribers\ConfirmationEmailCustomizer; use MailPoet\Subscribers\NewSubscriberNotificationMailer; use MailPoet\Subscribers\SubscriberListingRepository; use MailPoet\Tags\TagRepository; +use MailPoet\UnexpectedValueException; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\WooCommerce\Helper as WooCommerceHelper; use MailPoet\WP\Functions as WPFunctions; @@ -422,6 +424,417 @@ class Reporter { ]; } + public function getCampaignAnalyticsData(): array { + $matchingCampaignIds = [ + 'Number of standard newsletters sent in last 7 days' => [], + 'Number of standard newsletters sent in last 3 months' => [], + 'Number of standard newsletters sent in last 30 days' => [], + + 'Number of standard newsletters sent to segment in last 7 days' => [], + 'Number of standard newsletters sent to segment in last 30 days' => [], + 'Number of standard newsletters sent to segment in last 3 months' => [], + + 'Number of standard newsletters filtered by segment in last 7 days' => [], + 'Number of standard newsletters filtered by segment in last 30 days' => [], + 'Number of standard newsletters filtered by segment in last 3 months' => [], + + 'Number of automations campaigns sent in the last 7 days' => [], + 'Number of automations campaigns sent in the last 30 days' => [], + 'Number of automations campaigns sent in the last 3 months' => [], + + 'Number of automations campaigns sent to segment in the last 7 days' => [], + 'Number of automations campaigns sent to segment in the last 30 days' => [], + 'Number of automations campaigns sent to segment in the last 3 months' => [], + + 'Number of automations campaigns filtered by segment in the last 7 days' => [], + 'Number of automations campaigns filtered by segment in the last 30 days' => [], + 'Number of automations campaigns filtered by segment in the last 3 months' => [], + + 'Number of re-engagement campaigns sent in the last 7 days' => [], + 'Number of re-engagement campaigns sent in the last 30 days' => [], + 'Number of re-engagement campaigns sent in the last 3 months' => [], + 'Number of re-engagement campaigns sent to segment in the last 7 days' => [], + 'Number of re-engagement campaigns sent to segment in the last 30 days' => [], + 'Number of re-engagement campaigns sent to segment in the last 3 months' => [], + 'Number of re-engagement campaigns filtered by segment in the last 7 days' => [], + 'Number of re-engagement campaigns filtered by segment in the last 30 days' => [], + 'Number of re-engagement campaigns filtered by segment in the last 3 months' => [], + + 'Number of post notification campaigns sent in the last 7 days' => [], + 'Number of post notification campaigns sent in the last 30 days' => [], + 'Number of post notification campaigns sent in the last 3 months' => [], + 'Number of post notification campaigns sent to segment in the last 7 days' => [], + 'Number of post notification campaigns sent to segment in the last 30 days' => [], + 'Number of post notification campaigns sent to segment in the last 3 months' => [], + 'Number of post notification campaigns filtered by segment in the last 7 days' => [], + 'Number of post notification campaigns filtered by segment in the last 30 days' => [], + 'Number of post notification campaigns filtered by segment in the last 3 months' => [], + + // Legacy + 'Number of legacy welcome email campaigns sent in the last 7 days' => [], + 'Number of legacy welcome email campaigns sent in the last 30 days' => [], + 'Number of legacy welcome email campaigns sent in the last 3 months' => [], + + 'Number of legacy abandoned cart campaigns sent in the last 7 days' => [], + 'Number of legacy abandoned cart campaigns sent in the last 30 days' => [], + 'Number of legacy abandoned cart campaigns sent in the last 3 months' => [], + + 'Number of legacy first purchase campaigns sent in the last 7 days' => [], + 'Number of legacy first purchase campaigns sent in the last 30 days' => [], + 'Number of legacy first purchase campaigns sent in the last 3 months' => [], + + 'Number of legacy purchased in category campaigns sent in the last 7 days' => [], + 'Number of legacy purchased in category campaigns sent in the last 30 days' => [], + 'Number of legacy purchased in category campaigns sent in the last 3 months' => [], + + 'Number of legacy purchased product campaigns sent in the last 7 days' => [], + 'Number of legacy purchased product campaigns sent in the last 30 days' => [], + 'Number of legacy purchased product campaigns sent in the last 3 months' => [], + + // Totals + 'Number of campaigns sent in the last 7 days' => [], + 'Number of campaigns sent in the last 30 days' => [], + 'Number of campaigns sent in the last 3 months' => [], + 'Number of campaigns sent to segment in the last 7 days' => [], + 'Number of campaigns sent to segment in the last 30 days' => [], + 'Number of campaigns sent to segment in the last 3 months' => [], + 'Number of campaigns filtered by segment in the last 7 days' => [], + 'Number of campaigns filtered by segment in the last 30 days' => [], + 'Number of campaigns filtered by segment in the last 3 months' => [], + ]; + + $processedResults = $this->getProcessedCampaignAnalytics(); + + foreach ($processedResults as $campaignId => $processedResult) { + $isNewerThan7DaysAgo = $processedResult['sentLast7Days'] ?? false; + $isNewerThan30DaysAgo = $processedResult['sentLast30Days'] ?? false; + $isNewerThan3MonthsAgo = $processedResult['sentLast3Months'] ?? false; + + $newsletterType = $processedResult['newsletterType']; + + $wasSentToDynamicSegment = $processedResult['sentToSegment'] ?? false; + $wasFilteredBySegment = $processedResult['filteredBySegment'] ?? false; + + // Totals + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of campaigns sent to segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns sent to segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of campaigns filtered by segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of campaigns sent to segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } + + switch ($newsletterType) { + case NewsletterEntity::TYPE_STANDARD: + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of standard newsletters sent in last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters sent in last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters sent in last 3 months'][] = $campaignId; + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of standard newsletters filtered by segment in last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters filtered by segment in last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters filtered by segment in last 3 months'][] = $campaignId; + } + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of standard newsletters sent to segment in last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters sent to segment in last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters sent to segment in last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of standard newsletters sent in last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters sent in last 3 months'][] = $campaignId; + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of standard newsletters filtered by segment in last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters filtered by segment in last 3 months'][] = $campaignId; + } + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of standard newsletters sent to segment in last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of standard newsletters sent to segment in last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of standard newsletters sent in last 3 months'][] = $campaignId; + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of standard newsletters filtered by segment in last 3 months'][] = $campaignId; + } + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of standard newsletters sent to segment in last 3 months'][] = $campaignId; + } + } + break; + case NewsletterEntity::TYPE_NOTIFICATION_HISTORY: + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of post notification campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of post notification campaigns sent to segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns sent to segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of post notification campaigns filtered by segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of post notification campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of post notification campaigns sent to segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of post notification campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of post notification campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of post notification campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of post notification campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of post notification campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } + break; + case NewsletterEntity::TYPE_RE_ENGAGEMENT: + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of re-engagement campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of re-engagement campaigns sent to segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns sent to segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of re-engagement campaigns filtered by segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of re-engagement campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of re-engagement campaigns sent to segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of re-engagement campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of re-engagement campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of re-engagement campaigns sent in the last 3 months'][] = $campaignId; + if ($wasSentToDynamicSegment) { + $matchingCampaignIds['Number of re-engagement campaigns sent to segment in the last 3 months'][] = $campaignId; + } + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of re-engagement campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } + break; + case NewsletterEntity::TYPE_WELCOME: + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of legacy welcome email campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy welcome email campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy welcome email campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of legacy welcome email campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy welcome email campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of legacy welcome email campaigns sent in the last 3 months'][] = $campaignId; + } + break; + case NewsletterEntity::TYPE_AUTOMATION: + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of automations campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of automations campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of automations campaigns sent in the last 3 months'][] = $campaignId; + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of automations campaigns filtered by segment in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of automations campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of automations campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of automations campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of automations campaigns sent in the last 3 months'][] = $campaignId; + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of automations campaigns filtered by segment in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of automations campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of automations campaigns sent in the last 3 months'][] = $campaignId; + if ($wasFilteredBySegment) { + $matchingCampaignIds['Number of automations campaigns filtered by segment in the last 3 months'][] = $campaignId; + } + } + break; + // Legacy automatic emails. + case 'purchasedProduct': + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of legacy purchased product campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy purchased product campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy purchased product campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of legacy purchased product campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy purchased product campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of legacy purchased product campaigns sent in the last 3 months'][] = $campaignId; + } + break; + case 'purchasedInCategory': + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of legacy purchased in category campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy purchased in category campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy purchased in category campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of legacy purchased in category campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy purchased in category campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of legacy purchased in category campaigns sent in the last 3 months'][] = $campaignId; + } + break; + case 'abandonedCart': + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of legacy abandoned cart campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy abandoned cart campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy abandoned cart campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of legacy abandoned cart campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy abandoned cart campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of legacy abandoned cart campaigns sent in the last 3 months'][] = $campaignId; + } + break; + case 'firstPurchase': + if ($isNewerThan7DaysAgo) { + $matchingCampaignIds['Number of legacy first purchase campaigns sent in the last 7 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy first purchase campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy first purchase campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan30DaysAgo) { + $matchingCampaignIds['Number of legacy first purchase campaigns sent in the last 30 days'][] = $campaignId; + $matchingCampaignIds['Number of legacy first purchase campaigns sent in the last 3 months'][] = $campaignId; + } elseif ($isNewerThan3MonthsAgo) { + $matchingCampaignIds['Number of legacy first purchase campaigns sent in the last 3 months'][] = $campaignId; + } + break; + } + } + + $returnData = []; + + foreach ($matchingCampaignIds as $key => $campaignIds) { + $returnData[$key] = count(array_unique($campaignIds)); + } + + return $returnData; + } + + public function getProcessedCampaignAnalytics(): array { + $rawData = $this->newslettersRepository->getCampaignAnalyticsQuery()->getArrayResult(); + $processedResults = []; + + $sevenDaysAgo = Carbon::now()->subDays(7); + $thirtyDaysAgo = Carbon::now()->subDays(30); + $threeMonthsAgo = Carbon::now()->subMonths(3); + + foreach ($rawData as $sendingInfo) { + $meta = $sendingInfo['sendingQueueMeta']; + $campaignId = $meta['campaignId'] ?? null; + + if (!is_string($campaignId)) { + continue; + } + /** @var \DateTime $processedAt */ + $processedAt = $sendingInfo['processedAt']; + + if (!isset($processedResults[$campaignId])) { + $newsletterType = $sendingInfo['newsletterType']; + $processedData = [ + 'campaignId' => $campaignId, + 'newsletterType' => $newsletterType, + 'automaticSubType' => null, + 'sentToSegment' => $sendingInfo['segmentType'] === 'dynamic', + 'sentLast7Days' => $processedAt > $sevenDaysAgo, + 'sentLast30Days' => $processedAt > $thirtyDaysAgo, + 'sentLast3Months' => $processedAt > $threeMonthsAgo, + 'filteredBySegment' => !!($meta['filterSegment'] ?? null), + ]; + $processedResults[$campaignId] = $processedData; + if ($newsletterType === NewsletterEntity::TYPE_AUTOMATIC) { + try { + // Although we could determine the subtype by joining the appropriate newsletter option field, using + // the meta should be just as reliable, and we need the meta anyway, so this keeps our query simpler. + $subType = $this->getLegacyAutomaticEmailSubtypeFromMeta($meta); + $processedResults[$campaignId]['newsletterType'] = $subType; + } catch (UnexpectedValueException $e) { + // Ignore this error, the `automatic` email type won't be counted + } + } + } else { + $existingData = $processedResults[$campaignId]; + if ($sendingInfo['segmentType'] === 'dynamic') { + $processedResults[$campaignId]['sentToSegment'] = true; + } + if ($processedAt > $sevenDaysAgo) { + $processedResults[$campaignId]['sentLast7Days'] = true; + } + if ($processedAt > $thirtyDaysAgo) { + $processedResults[$campaignId]['sentLast30Days'] = true; + } + if ($processedAt > $threeMonthsAgo) { + $processedResults[$campaignId]['sentLast3Months'] = true; + } + } + } + + return $processedResults; + } + + private function getLegacyAutomaticEmailSubtypeFromMeta(array $meta): string { + if (array_key_exists('orderedProducts', $meta)) { + return 'purchasedProduct'; + } + if (array_key_exists('orderedProductCategories', $meta)) { + return 'purchasedInCategory'; + } + if (array_key_exists('cart_product_ids', $meta)) { + return 'abandonedCart'; + } + if (array_key_exists('order_amount', $meta) && array_key_exists('order_date', $meta) && array_key_exists('order_id', $meta)) { + return 'firstPurchase'; + } + + throw new UnexpectedValueException('Unknown automatic email type based on meta data'); + } + private function isFilterTypeActive(string $filterType, string $action): bool { if ($this->dynamicSegmentFilterRepository->findOnyByFilterTypeAndAction($filterType, $action)) { return true; diff --git a/mailpoet/lib/Newsletter/NewslettersRepository.php b/mailpoet/lib/Newsletter/NewslettersRepository.php index e9b2403466..d0165ab219 100644 --- a/mailpoet/lib/Newsletter/NewslettersRepository.php +++ b/mailpoet/lib/Newsletter/NewslettersRepository.php @@ -156,6 +156,25 @@ class NewslettersRepository extends Repository { ->getSingleScalarResult() ?: 0; } + public function getCampaignAnalyticsQuery() { + return $this->doctrineRepository->createQueryBuilder('n') + ->select(' + n.type as newsletterType, + q.meta as sendingQueueMeta, + s.type as segmentType, + t.processedAt', + ) + ->join('n.queues', 'q') + ->join('q.task', 't') + ->leftJoin('n.newsletterSegments', 'ns') + ->leftJoin('ns.segment', 's') + ->andWhere('t.status = :taskStatus') + ->andWhere('t.processedAt >= :since') + ->setParameter('taskStatus', ScheduledTaskEntity::STATUS_COMPLETED) + ->setParameter('since', Carbon::now()->subDays(90)) + ->getQuery(); + } + public function getAnalytics(): array { // for automatic emails join 'event' newsletter option to further group the counts $eventOptionId = (int)$this->entityManager->createQueryBuilder() diff --git a/mailpoet/tests/DataFactories/Newsletter.php b/mailpoet/tests/DataFactories/Newsletter.php index 09cd0a0f7f..26198fae9a 100644 --- a/mailpoet/tests/DataFactories/Newsletter.php +++ b/mailpoet/tests/DataFactories/Newsletter.php @@ -484,6 +484,9 @@ class Newsletter { if ($queue['processed_at'] ?? null) { $scheduledTask->setProcessedAt($queue['processed_at']); } + if ($queue['meta']) { + $sendingQueue->setMeta($queue['meta']); + } $entityManager->persist($sendingQueue); $sendingQueue->setNewsletter($newsletter); $scheduledTask->setStatus($queue['status']); diff --git a/mailpoet/tests/integration/Analytics/ReporterTest.php b/mailpoet/tests/integration/Analytics/ReporterTest.php new file mode 100644 index 0000000000..97de45d672 --- /dev/null +++ b/mailpoet/tests/integration/Analytics/ReporterTest.php @@ -0,0 +1,276 @@ +reporter = $this->diContainer->get(Reporter::class); + } + + public function testItWorksWithStandardNewslettersAndStandardSegments(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of standard newsletters sent in last 7 days']); + $this->assertEquals(2, $processed['Number of standard newsletters sent in last 30 days']); + $this->assertEquals(3, $processed['Number of standard newsletters sent in last 3 months']); + } + + public function testItWorksWithStandardNewslettersAndDynamicSegments(): void { + $dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of standard newsletters sent in last 7 days']); + $this->assertEquals(2, $processed['Number of standard newsletters sent in last 30 days']); + $this->assertEquals(3, $processed['Number of standard newsletters sent in last 3 months']); + $this->assertEquals(1, $processed['Number of standard newsletters sent to segment in last 7 days']); + $this->assertEquals(2, $processed['Number of standard newsletters sent to segment in last 30 days']); + $this->assertEquals(3, $processed['Number of standard newsletters sent to segment in last 3 months']); + } + + public function testItWorksWithStandardNewslettersAndFilterSegments(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of standard newsletters sent in last 7 days']); + $this->assertEquals(2, $processed['Number of standard newsletters sent in last 30 days']); + $this->assertEquals(3, $processed['Number of standard newsletters sent in last 3 months']); + $this->assertEquals(1, $processed['Number of standard newsletters filtered by segment in last 7 days']); + $this->assertEquals(2, $processed['Number of standard newsletters filtered by segment in last 30 days']); + $this->assertEquals(3, $processed['Number of standard newsletters filtered by segment in last 3 months']); + $this->assertEquals(0, $processed['Number of standard newsletters sent to segment in last 7 days']); + $this->assertEquals(0, $processed['Number of standard newsletters sent to segment in last 30 days']); + $this->assertEquals(0, $processed['Number of standard newsletters sent to segment in last 3 months']); + } + + public function testItWorksWithNotificationHistoryNewsletters(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']); + $this->assertEquals(2, $processed['Number of post notification campaigns sent in the last 30 days']); + $this->assertEquals(3, $processed['Number of post notification campaigns sent in the last 3 months']); + } + + public function testItWorksWithNotificationHistoryNewslettersSentToSegments(): void { + $dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']); + $this->assertEquals(2, $processed['Number of post notification campaigns sent in the last 30 days']); + $this->assertEquals(3, $processed['Number of post notification campaigns sent in the last 3 months']); + $this->assertEquals(1, $processed['Number of post notification campaigns sent to segment in the last 7 days']); + $this->assertEquals(2, $processed['Number of post notification campaigns sent to segment in the last 30 days']); + $this->assertEquals(3, $processed['Number of post notification campaigns sent to segment in the last 3 months']); + } + + public function testItWorksWithNotificationHistoryNewslettersFilteredBySegment(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'filterSegment' => ['not' => 'relevant']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'filterSegment' => ['not' => 'relevant']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['not' => 'relevant']]]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']); + $this->assertEquals(2, $processed['Number of post notification campaigns sent in the last 30 days']); + $this->assertEquals(3, $processed['Number of post notification campaigns sent in the last 3 months']); + $this->assertEquals(1, $processed['Number of post notification campaigns filtered by segment in the last 7 days']); + $this->assertEquals(2, $processed['Number of post notification campaigns filtered by segment in the last 30 days']); + $this->assertEquals(3, $processed['Number of post notification campaigns filtered by segment in the last 3 months']); + $this->assertEquals(0, $processed['Number of post notification campaigns sent to segment in the last 7 days']); + $this->assertEquals(0, $processed['Number of post notification campaigns sent to segment in the last 30 days']); + $this->assertEquals(0, $processed['Number of post notification campaigns sent to segment in the last 3 months']); + } + + public function testItWorksWithReEngagementEmails(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of re-engagement campaigns sent in the last 7 days']); + $this->assertEquals(2, $processed['Number of re-engagement campaigns sent in the last 30 days']); + $this->assertEquals(3, $processed['Number of re-engagement campaigns sent in the last 3 months']); + } + + public function testItWorksWithReEngagementEmailsSentToSegment(): void { + $dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of re-engagement campaigns sent in the last 7 days']); + $this->assertEquals(2, $processed['Number of re-engagement campaigns sent in the last 30 days']); + $this->assertEquals(3, $processed['Number of re-engagement campaigns sent in the last 3 months']); + $this->assertEquals(1, $processed['Number of re-engagement campaigns sent to segment in the last 7 days']); + $this->assertEquals(2, $processed['Number of re-engagement campaigns sent to segment in the last 30 days']); + $this->assertEquals(3, $processed['Number of re-engagement campaigns sent to segment in the last 3 months']); + } + + public function testItWorksWithReEngagementEmailsFilteredBySegment(): void { + $dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of re-engagement campaigns sent in the last 7 days']); + $this->assertEquals(2, $processed['Number of re-engagement campaigns sent in the last 30 days']); + $this->assertEquals(3, $processed['Number of re-engagement campaigns sent in the last 3 months']); + $this->assertEquals(1, $processed['Number of re-engagement campaigns filtered by segment in the last 7 days']); + $this->assertEquals(2, $processed['Number of re-engagement campaigns filtered by segment in the last 30 days']); + $this->assertEquals(3, $processed['Number of re-engagement campaigns filtered by segment in the last 3 months']); + $this->assertEquals(0, $processed['Number of re-engagement campaigns sent to segment in the last 7 days']); + $this->assertEquals(0, $processed['Number of re-engagement campaigns sent to segment in the last 30 days']); + $this->assertEquals(0, $processed['Number of re-engagement campaigns sent to segment in the last 3 months']); + } + + public function testItWorksWithLegacyWelcomeEmails(): void { + $this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + $this->assertSame(1, $processed['Number of legacy welcome email campaigns sent in the last 7 days']); + $this->assertSame(2, $processed['Number of legacy welcome email campaigns sent in the last 30 days']); + $this->assertSame(3, $processed['Number of legacy welcome email campaigns sent in the last 3 months']); + } + + public function testItWorksWithLegacyAbandonedCartEmails(): void { + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'cart_product_ids' => ['123']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'cart_product_ids' => ['1234']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'cart_product_ids' => ['1235']]]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + $this->assertSame(1, $processed['Number of legacy abandoned cart campaigns sent in the last 7 days']); + $this->assertSame(2, $processed['Number of legacy abandoned cart campaigns sent in the last 30 days']); + $this->assertSame(3, $processed['Number of legacy abandoned cart campaigns sent in the last 3 months']); + } + + public function testItWorksWithLegacyPurchasedProductEmails(): void { + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'orderedProducts' => ['123']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'orderedProducts' => ['1234']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProducts' => ['1235']]]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + $this->assertSame(1, $processed['Number of legacy purchased product campaigns sent in the last 7 days']); + $this->assertSame(2, $processed['Number of legacy purchased product campaigns sent in the last 30 days']); + $this->assertSame(3, $processed['Number of legacy purchased product campaigns sent in the last 3 months']); + } + + public function testItWorksWithLegacyPurchasedInCategoryEmails(): void { + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'orderedProductCategories' => ['123']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'orderedProductCategories' => ['1234']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProductCategories' => ['1235']]]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + $this->assertSame(1, $processed['Number of legacy purchased in category campaigns sent in the last 7 days']); + $this->assertSame(2, $processed['Number of legacy purchased in category campaigns sent in the last 30 days']); + $this->assertSame(3, $processed['Number of legacy purchased in category campaigns sent in the last 3 months']); + } + + public function testItWorksWithLegacyFirstPurchaseEmails(): void { + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '3']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + $this->assertSame(1, $processed['Number of legacy first purchase campaigns sent in the last 7 days']); + $this->assertSame(2, $processed['Number of legacy first purchase campaigns sent in the last 30 days']); + $this->assertSame(3, $processed['Number of legacy first purchase campaigns sent in the last 3 months']); + } + + public function testItWorksForAutomationEmails(): void { + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'orderedProductCategories' => ['123']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'orderedProductCategories' => ['1234']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProductCategories' => ['1235']]]]); + + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertSame(1, $processed['Number of automations campaigns sent in the last 7 days']); + $this->assertSame(2, $processed['Number of automations campaigns sent in the last 30 days']); + $this->assertSame(3, $processed['Number of automations campaigns sent in the last 3 months']); + } + + public function testItReportsSentCampaignTotals(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]); + + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '4']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '5']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '6']]]); + + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '7', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '8', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '9', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]); + + $processed = $this->reporter->getCampaignAnalyticsData(); + $this->assertEquals(3, $processed['Number of campaigns sent in the last 7 days']); + $this->assertEquals(6, $processed['Number of campaigns sent in the last 30 days']); + $this->assertEquals(9, $processed['Number of campaigns sent in the last 3 months']); + + $this->assertEquals(1, $processed['Number of campaigns sent to segment in the last 7 days']); + $this->assertEquals(2, $processed['Number of campaigns sent to segment in the last 30 days']); + $this->assertEquals(3, $processed['Number of campaigns sent to segment in the last 3 months']); + + $this->assertEquals(1, $processed['Number of campaigns filtered by segment in the last 7 days']); + $this->assertEquals(2, $processed['Number of campaigns filtered by segment in the last 30 days']); + $this->assertEquals(3, $processed['Number of campaigns filtered by segment in the last 3 months']); + } + + public function testItDoesNotDoubleCountDuplicateCampaignIds(): void { + $defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create(); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]); + $processed = $this->reporter->getCampaignAnalyticsData(); + + $this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']); + $this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 30 days']); + $this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 3 months']); + } + + public function testItCanDetermineIfAnAutomationWasFilteredBySegment(): void { + } + + private function createSentNewsletter(string $type, Carbon $sentAt, array $segments, array $otherOptions = []): void { + $sendingQueueOptions = ['processed_at' => $sentAt]; + + $extraSendingQueueOptions = $otherOptions['sendingQueueOptions'] ?? null; + + if (is_array($extraSendingQueueOptions)) { + $sendingQueueOptions = array_merge($sendingQueueOptions, $extraSendingQueueOptions); + } + + (new NewsletterFactory()) + ->withType($type) + ->withSegments($segments) + ->withSendingQueue($sendingQueueOptions) + ->withStatus(NewsletterEntity::STATUS_SENT) + ->create(); + } +}