diff --git a/core/ReportRenderer/Pdf.php b/core/ReportRenderer/Pdf.php index 07239811dd6..fa25a4cb5f9 100644 --- a/core/ReportRenderer/Pdf.php +++ b/core/ReportRenderer/Pdf.php @@ -28,7 +28,6 @@ */ class Pdf extends ReportRenderer { - public const IMAGE_GRAPH_WIDTH_LANDSCAPE = 1050; public const IMAGE_GRAPH_WIDTH_PORTRAIT = 760; public const IMAGE_GRAPH_HEIGHT = 220; @@ -46,22 +45,24 @@ class Pdf extends ReportRenderer public const PDF_CONTENT_TYPE = 'pdf'; private $reportFontStyle = ''; - private $reportSimpleFontSize = 9; + private $reportSimpleFontSize = 8.5; private $reportHeaderFontSize = 16; private $cellHeight = 6; private $bottomMargin = 17; private $reportWidthPortrait = 195; - private $reportWidthLandscape = 270; - private $minWidthLabelCell = 100; - private $maxColumnCountPortraitOrientation = 6; + private $minWidthLabelCellPortrait = 80; + private $minWidthLabelCellPortraitShort = 65; private $logoWidth = 16; private $logoHeight = 16; private $totalWidth; private $cellWidth; private $labelCellWidth; - private $truncateAfter = 55; + private $maxRowHeight = 13; + private $maxLabelCharacter = 135; private $leftSpacesBeforeLogo = 7; private $logoImagePosition = array(10, 40); + private $headerBottomPadding = 2; + private $headerBottomPaddingShort = 0.5; private $headerTextColor; private $reportTextColor; private $tableHeaderBackgroundColor; @@ -80,6 +81,9 @@ class Pdf extends ReportRenderer private $reportFont = ReportRenderer::DEFAULT_REPORT_FONT_FAMILY; private $TCPDF; private $orientation = self::PORTRAIT; + private $labelShortContentThreshold = 100; + private $columnCellWidths = array(); + private $labelThirdLinePadding = 4; public function __construct() { @@ -279,12 +283,9 @@ private function paintReportHeader() // Table-only reports with more than 2 columns are always landscape if ($tableOnlyManyColumnReport) { $tableOnlyManyColumnReportRowCount = 0; - $this->orientation = self::LANDSCAPE; - } else { - // Graph-only reports are always portrait - $this->orientation = $graphOnlyReport ? self::PORTRAIT : ($columnCount > $this->maxColumnCountPortraitOrientation ? self::LANDSCAPE : self::PORTRAIT); } - + // Scheduled reports should never switch to landscape layouts to keep a consistent portrait output + $this->orientation = self::PORTRAIT; $this->TCPDF->setPageOrientation($this->orientation, '', $this->bottomMargin); } @@ -343,12 +344,32 @@ public function renderReport($processedReport) } } - private function formatText($text) + /** + * @param $text + * @return string + */ + private function formatText($text): string { return Common::unsanitizeInputValue($text); } - private function paintReportTable() + /** + * @param $text + * @param $maxLength + * @return string + */ + private function limitTextLength($text, $maxLength): string + { + if (mb_strlen($text) <= $maxLength) { + return $text; + } + return mb_substr($text, 0, $maxLength) . '...'; + } + + /** + * @return void + */ + private function paintReportTable(): void { //Color and font restoration $this->TCPDF->SetFillColor($this->tableBackgroundColor[0], $this->tableBackgroundColor[1], $this->tableBackgroundColor[2]); @@ -367,10 +388,12 @@ private function paintReportTable() // Draw a body of report table foreach ($this->report->getRows() as $rowId => $row) { $rowMetrics = $row->getColumns(); + $url = false; $rowMetadata = isset($rowsMetadata[$rowId]) ? $rowsMetadata[$rowId]->getColumns() : array(); if (isset($rowMetadata['url'])) { $url = $rowMetadata['url']; } + $rowHeight = $this->cellHeight; foreach ($this->reportColumns as $columnId => $columnName) { // Label column if ($columnId == 'label') { @@ -379,14 +402,40 @@ private function paintReportTable() $posX = $this->TCPDF->GetX(); $posY = $this->TCPDF->GetY(); if (isset($rowMetrics[$columnId])) { - $text = mb_substr($rowMetrics[$columnId], 0, $this->truncateAfter); + $text = $rowMetrics[$columnId]; + $urlString = $this->isUrl($text); + if (!$url && $urlString !== false) { + $url = $urlString; + } + $text = $this->limitTextLength($text, $this->maxLabelCharacter); if ($isLogoDisplayable) { $text = $leftSpacesBeforeLogo . $text; } } $text = $this->formatText($text); - - $this->TCPDF->Cell($this->labelCellWidth, $this->cellHeight, $text, 'LR', 0, 'L', $fill, $url); + $rowHeight = $this->getLabelRowHeight($text); + $maxHeight = $this->getLabelRowMaxHeight($rowHeight); + $this->TCPDF->MultiCell( + $this->labelCellWidth, + $rowHeight, + $text, + 'LR', + 'L', + $fill, + 0, + '', + '', + true, + 0, + false, + true, + $maxHeight, + 'M' + ); + if ($url) { + $this->TCPDF->Link($posX, $posY, $this->labelCellWidth, $rowHeight, $url); + } + $this->TCPDF->SetXY($posX + $this->labelCellWidth, $posY); if ($isLogoDisplayable) { if (isset($rowMetadata['logoWidth'])) { @@ -417,7 +466,16 @@ private function paintReportTable() if (empty($rowMetrics[$columnId])) { $rowMetrics[$columnId] = 0; } - $this->TCPDF->Cell($this->cellWidth, $this->cellHeight, NumberFormatter::getInstance()->format($rowMetrics[$columnId]), 'LR', 0, 'L', $fill); + $columnWidth = $this->getColumnWidth($columnId); + $this->TCPDF->Cell( + $columnWidth, + $rowHeight, + NumberFormatter::getInstance()->format($rowMetrics[$columnId]), + 'LR', + 0, + 'L', + $fill + ); } } @@ -433,11 +491,276 @@ private function paintReportTable() } } - private function paintGraph() + /** + * Gets the row height for a label. This will be the total height including wrapping + * but still having a maximum height + * @param string $text + * @return float + */ + private function getLabelRowHeight(string $text): float + { + $maxHeight = $this->maxRowHeight; + $labelHeight = $this->TCPDF->getStringHeight($this->labelCellWidth, $text); + $labelHeight = ceil($labelHeight * 2) / 2; // round up to nearest 0.5 for stable row heights + + if ($labelHeight > $maxHeight) { + return $maxHeight; + } + + if ($labelHeight < $this->cellHeight) { + return $this->cellHeight; + } + + return $labelHeight + 1; + } + + /** + * Checks if a string might be a url or not + * Will return the string with an 'https' protocol if it is a valid url + * @param string $value + * @return false|string + */ + private function isUrl(string $value) + { + $candidate = $value; + if (!preg_match('~^[a-z][a-z0-9+.-]*://~i', $candidate)) { + $candidate = 'https://' . $candidate; + } + $host = parse_url($candidate, PHP_URL_HOST); + $isValidHost = $host && strpos($host, '.') !== false; + $isValidUrl = filter_var($candidate, FILTER_VALIDATE_URL) !== false && $isValidHost; + return $isValidUrl ? $candidate : false; + } + + /** + * This is only useful when label row is 3 lines, + * we needed to make max row bigger so that it can be centered vertically better + * @param float $rowHeight + * @return float + */ + private function getLabelRowMaxHeight(float $rowHeight): float + { + if ($rowHeight >= $this->maxRowHeight) { + return $rowHeight + $this->labelThirdLinePadding; + } + return $rowHeight; + } + + /** + * Will check whether label should use a shorter width or not + * @param int $columnsCount + * @return void + */ + private function adjustLabelWidthForTableData(int $columnsCount): void + { + if ($columnsCount <= 1 || !$this->reportHasData()) { + return; + } + + if (!$this->shouldUseShortLabelWidth()) { + return; + } + + $this->labelCellWidth = $this->minWidthLabelCellPortraitShort; + $this->cellWidth = round(($this->totalWidth - $this->labelCellWidth) / ($columnsCount - 1)); + $this->totalWidth = $this->labelCellWidth + ($columnsCount - 1) * $this->cellWidth; + } + + /** + * Grabs adjusted column widths + * @param string $columnId + * @return float + */ + private function getColumnWidth(string $columnId): float + { + if (isset($this->columnCellWidths[$columnId])) { + return (float) $this->columnCellWidths[$columnId]; + } + + if ($columnId === 'label') { + return (float) $this->labelCellWidth; + } + + return (float) $this->cellWidth; + } + + /** + * This function will try to show all values for revenue columns. + * Will adjust other column widths to accommodate this + * @return void + */ + private function adjustMetricColumnWidthsForRevenue(): void + { + if (!$this->reportHasData()) { + return; + } + + $revenueColumns = array('revenue', 'ecommerce_revenue'); + $this->TCPDF->SetFont($this->reportFont, $this->reportFontStyle, $this->reportSimpleFontSize); + + foreach ($revenueColumns as $columnId) { + $this->adjustMetricColumnWidthToContent($columnId); + } + } + + /** + * This function will try to adjust column width based on the content. + * This will try to make other columns smaller to accommodate this + * @param string $columnId + * @return void + */ + private function adjustMetricColumnWidthToContent(string $columnId): void + { + if (!array_key_exists($columnId, $this->reportColumns) || !isset($this->columnCellWidths[$columnId])) { + return; + } + + $requiredWidth = $this->getMaxFormattedColumnWidth($columnId); + if ($requiredWidth <= 0) { + return; + } + + $currentWidth = $this->columnCellWidths[$columnId]; + if ($requiredWidth <= $currentWidth) { + return; + } + + $additionalWidth = $requiredWidth - $currentWidth; + $remainingWidthToGain = $additionalWidth; + + $adjustableColumns = array(); + foreach ($this->columnCellWidths as $otherColumnId => $width) { + if ($otherColumnId === 'label' || $otherColumnId === $columnId) { + continue; + } + if ($width <= 0) { + continue; + } + $adjustableColumns[$otherColumnId] = $width; + } + + while ($remainingWidthToGain > 0 && !empty($adjustableColumns)) { + $share = $remainingWidthToGain / count($adjustableColumns); + $updatedColumns = array(); + + foreach ($adjustableColumns as $otherColumnId => $availableWidth) { + $reduction = min($availableWidth, $share); + if ($reduction <= 0) { + continue; + } + $this->columnCellWidths[$otherColumnId] -= $reduction; + $remainingWidthToGain -= $reduction; + + $newWidth = $availableWidth - $reduction; + if ($newWidth > 0 && $remainingWidthToGain > 0) { + $updatedColumns[$otherColumnId] = $newWidth; + } + + if ($remainingWidthToGain <= 0) { + break 2; + } + } + + $adjustableColumns = $updatedColumns; + } + + $appliedWidth = $additionalWidth - $remainingWidthToGain; + if ($appliedWidth <= 0) { + return; + } + + $this->columnCellWidths[$columnId] += $appliedWidth; + } + + /** + * Computes maximum column width for a given metric column + * @param string $columnId + * @return float + */ + private function getMaxFormattedColumnWidth(string $columnId): float + { + $maxWidth = 0; + + foreach ($this->report->getRows() as $row) { + $value = $row->getColumn($columnId); + if ($value === false || $value === null) { + continue; + } + $formattedValue = NumberFormatter::getInstance()->format($value); + $width = $this->TCPDF->GetStringWidth($formattedValue); + if ($width > $maxWidth) { + $maxWidth = $width; + } + } + + if ($maxWidth <= 0) { + return 0; + } + + return $maxWidth + 2; + } + + /** + * Will check if label column could use a shorter width. + * This is done so that we can fit more metrics in the same row for data table with no label that is too long + * @return bool + */ + private function shouldUseShortLabelWidth(): bool + { + $this->TCPDF->SetFont($this->reportFont, $this->reportFontStyle, $this->reportSimpleFontSize); + + $maxCharacters = $this->maxLabelCharacter; + + $rowsMetadata = array(); + if (!empty($this->reportRowsMetadata)) { + $rowsMetadata = $this->reportRowsMetadata->getRows(); + } + + $maxLength = 0; + foreach ($this->report->getRows() as $rowId => $row) { + $label = $row->getColumn('label'); + if ($label === false || $label === null) { + continue; + } + $rawLabel = (string) $label; + $visibleLabel = mb_substr($rawLabel, 0, $maxCharacters); + + if (mb_strlen($rawLabel) > mb_strlen($visibleLabel)) { + return false; + } + + $length = mb_strlen($visibleLabel); + if ($length > $maxLength) { + $maxLength = $length; + if ($maxLength >= $this->labelShortContentThreshold) { + return false; + } + } + if (isset($rowsMetadata[$rowId])) { + $rowMeta = $rowsMetadata[$rowId]->getColumns(); + if (isset($rowMeta['logo'])) { + $visibleLabel = str_repeat(' ', $this->leftSpacesBeforeLogo) . $visibleLabel; + } + } + + $formattedLabel = $this->formatText($visibleLabel); + if ($this->TCPDF->getNumLines($formattedLabel, $this->labelCellWidth) > 1) { + return false; + } + } + + return $maxLength > 0; + } + + /** + * @return void + * @throws \Exception + */ + private function paintGraph(): void { $imageGraph = parent::getStaticGraph( $this->reportMetadata, - $this->orientation == self::PORTRAIT ? self::IMAGE_GRAPH_WIDTH_PORTRAIT : self::IMAGE_GRAPH_WIDTH_LANDSCAPE, + $this->orientation == self::IMAGE_GRAPH_WIDTH_PORTRAIT, self::IMAGE_GRAPH_HEIGHT, $this->evolutionGraph, $this->segment @@ -471,72 +794,200 @@ private function paintGraph() /** * Draw the table header (first row) */ - private function paintReportTableHeader() + private function paintReportTableHeader(): void { $initPosX = 10; - // Get the longest column name - $longestColumnName = ''; - foreach ($this->reportColumns as $columnName) { - if (strlen($columnName) > strlen($longestColumnName)) { - $longestColumnName = $columnName; - } - } + $this->initializeTableColumnWidths(); + $this->setupHeaderRenderingStyle(); + + $posY = $this->TCPDF->GetY(); + list($columnData, $maxCellHeight) = $this->buildHeaderColumnData(); + + $this->TCPDF->SetXY($initPosX, $posY); + $this->renderHeaderColumns($columnData, $initPosX, $posY, $maxCellHeight); + $extraSpacing = 1; + $this->TCPDF->Ln($extraSpacing); + $this->TCPDF->SetXY($initPosX, $posY + $maxCellHeight + $extraSpacing); + } + + /** + * Will initialize table column widths, + * this will include adjusting label and revenue columns + * @return void + */ + private function initializeTableColumnWidths(): void + { $columnsCount = count($this->reportColumns); - // Computes available column width - if ( - $this->orientation == self::PORTRAIT - && $columnsCount <= 3 - ) { - $totalWidth = $this->reportWidthPortrait * 2 / 3; - } elseif ($this->orientation == self::LANDSCAPE) { - $totalWidth = $this->reportWidthLandscape; - } else { - $totalWidth = $this->reportWidthPortrait; - } - $this->totalWidth = $totalWidth; - $this->labelCellWidth = max(round(($this->totalWidth / $columnsCount)), $this->minWidthLabelCell); - $this->cellWidth = round(($this->totalWidth - $this->labelCellWidth) / ($columnsCount - 1)); - $this->totalWidth = $this->labelCellWidth + ($columnsCount - 1) * $this->cellWidth; + if ($columnsCount === 0) { + return; + } + + $this->totalWidth = $this->reportWidthPortrait; + $minLabelWidth = $this->minWidthLabelCellPortrait; + $this->labelCellWidth = max(round($this->totalWidth / $columnsCount), $minLabelWidth); + + $metricColumns = max(1, $columnsCount - 1); + $this->cellWidth = round(($this->totalWidth - $this->labelCellWidth) / $metricColumns); + $this->totalWidth = $this->labelCellWidth + $metricColumns * $this->cellWidth; + + $this->adjustLabelWidthForTableData($columnsCount); + + $this->columnCellWidths = array(); + foreach ($this->reportColumns as $columnId => $_) { + $this->columnCellWidths[$columnId] = $columnId === 'label' ? $this->labelCellWidth : $this->cellWidth; + } - $this->TCPDF->SetFillColor($this->tableHeaderBackgroundColor[0], $this->tableHeaderBackgroundColor[1], $this->tableHeaderBackgroundColor[2]); - $this->TCPDF->SetTextColor($this->tableHeaderTextColor[0], $this->tableHeaderTextColor[1], $this->tableHeaderTextColor[2]); + $this->adjustMetricColumnWidthsForRevenue(); + $this->totalWidth = array_sum($this->columnCellWidths); + } + + /** + * @return void + */ + private function setupHeaderRenderingStyle(): void + { + $this->TCPDF->SetFillColor( + $this->tableHeaderBackgroundColor[0], + $this->tableHeaderBackgroundColor[1], + $this->tableHeaderBackgroundColor[2] + ); + $this->TCPDF->SetTextColor( + $this->tableHeaderTextColor[0], + $this->tableHeaderTextColor[1], + $this->tableHeaderTextColor[2] + ); $this->TCPDF->SetLineWidth(.3); $this->setBorderColor(); - $this->TCPDF->SetFont($this->reportFont, $this->reportFontStyle); + $this->TCPDF->SetFont($this->reportFont, 'B'); $this->TCPDF->SetFillColor(255); - $this->TCPDF->SetTextColor($this->tableHeaderBackgroundColor[0], $this->tableHeaderBackgroundColor[1], $this->tableHeaderBackgroundColor[2]); + $this->TCPDF->SetTextColor( + $this->tableHeaderBackgroundColor[0], + $this->tableHeaderBackgroundColor[1], + $this->tableHeaderBackgroundColor[2] + ); $this->TCPDF->SetDrawColor(255); + } - $posY = $this->TCPDF->GetY(); - $this->TCPDF->MultiCell($this->cellWidth, $this->cellHeight, $longestColumnName, 1, 'C', true); - $maxCellHeight = $this->TCPDF->GetY() - $posY; + /** + * Will adjust table headers based on their column name and make them be closer to the table + * @return array + */ + private function buildHeaderColumnData(): array + { + $columnData = array(); + $maxCellHeight = $this->cellHeight; - $this->TCPDF->SetFillColor($this->tableHeaderBackgroundColor[0], $this->tableHeaderBackgroundColor[1], $this->tableHeaderBackgroundColor[2]); - $this->TCPDF->SetTextColor($this->tableHeaderTextColor[0], $this->tableHeaderTextColor[1], $this->tableHeaderTextColor[2]); - $this->TCPDF->SetDrawColor($this->tableCellBorderColor[0], $this->tableCellBorderColor[1], $this->tableCellBorderColor[2]); + foreach ($this->reportColumns as $columnId => $columnName) { + $columnName = $this->formatText($columnName); + $columnWidth = $this->getColumnWidth($columnId); + $textHeight = $this->TCPDF->getStringHeight($columnWidth, $columnName); + $cellHeight = max($textHeight, $this->cellHeight); + + $columnData[] = array( + 'text' => $columnName, + 'width' => $columnWidth, + 'height' => $cellHeight, + 'textHeight' => $textHeight, + ); + + if ($cellHeight > $maxCellHeight) { + $maxCellHeight = $cellHeight; + } + } - $this->TCPDF->SetXY($initPosX, $posY); + return array($columnData, $maxCellHeight); + } - $countColumns = 0; - $posX = $initPosX; - foreach ($this->reportColumns as $columnName) { - $columnName = $this->formatText($columnName); + /** + * @param array $columnData + * @param float $initPosX + * @param float $posY + * @param float $maxCellHeight + * @return void + */ + private function renderHeaderColumns(array $columnData, float $initPosX, float $posY, float $maxCellHeight): void + { + $this->TCPDF->SetFillColor( + $this->tableHeaderBackgroundColor[0], + $this->tableHeaderBackgroundColor[1], + $this->tableHeaderBackgroundColor[2] + ); + $this->TCPDF->SetTextColor( + $this->tableHeaderTextColor[0], + $this->tableHeaderTextColor[1], + $this->tableHeaderTextColor[2] + ); + $this->TCPDF->SetDrawColor( + $this->tableCellBorderColor[0], + $this->tableCellBorderColor[1], + $this->tableCellBorderColor[2] + ); - //Label column - if ($countColumns == 0) { - $this->TCPDF->MultiCell($this->labelCellWidth, $maxCellHeight, $columnName, $border = 0, $align = 'L', true); - $this->TCPDF->SetXY($posX + $this->labelCellWidth, $posY); - } else { - $this->TCPDF->MultiCell($this->cellWidth, $maxCellHeight, $columnName, $border = 0, $align = 'L', true); - $this->TCPDF->SetXY($posX + $this->cellWidth, $posY); - } - $countColumns++; + $posX = $initPosX; + foreach ($columnData as $columnInfo) { + $columnWidth = $columnInfo['width']; + $textHeight = $columnInfo['textHeight']; + + $this->TCPDF->Rect($posX, $posY, $columnWidth, $maxCellHeight, 'F'); + + $textPosY = $this->calculateHeaderTextY($posY, $maxCellHeight, $textHeight); + $this->TCPDF->SetXY($posX, $textPosY); + $this->TCPDF->MultiCell( + $columnWidth, + $this->cellHeight, + $columnInfo['text'], + 0, + 'L', + false, + 0, + '', + '', + true, + 0, + false, + true, + 0, + 'T' + ); + $this->TCPDF->SetXY($posX + $columnWidth, $posY); $posX = $this->TCPDF->GetX(); } - $this->TCPDF->Ln(); - $this->TCPDF->SetXY($initPosX, $posY + $maxCellHeight); + } + + /** + * @param float $posY + * @param float $maxCellHeight + * @param float $textHeight + * @return float + */ + private function calculateHeaderTextY(float $posY, float $maxCellHeight, float $textHeight): float + { + if ($textHeight <= 0) { + $textHeight = $this->cellHeight; + } + + $bottomPadding = $this->headerBottomPadding; + if ($textHeight <= $this->cellHeight) { + $bottomPadding = 0; + } elseif ($textHeight <= $this->cellHeight * 2) { + $bottomPadding = $this->headerBottomPaddingShort; + } + + $availableSpace = max(0, $maxCellHeight - $textHeight); + $textPosY = $posY + $availableSpace - $bottomPadding; + + $minY = $posY; + $maxY = $posY + $maxCellHeight - $textHeight; + if ($textPosY < $minY) { + return $minY; + } + if ($textPosY > $maxY) { + return $maxY; + } + + return $textPosY; } /** @@ -545,7 +996,7 @@ private function paintReportTableHeader() * @param string $message * @return void */ - private function paintMessage($message) + private function paintMessage($message): void { $this->TCPDF->SetFont($this->reportFont, $this->reportFontStyle, $this->reportSimpleFontSize); $this->TCPDF->SetTextColor($this->reportTextColor[0], $this->reportTextColor[1], $this->reportTextColor[2]); @@ -562,7 +1013,7 @@ private function paintMessage($message) * @param $prettyDate * @return array */ - public function getAttachments($report, $processedReports, $prettyDate) + public function getAttachments($report, $processedReports, $prettyDate): array { return array(); } diff --git a/plugins/CustomDimensions/tests/System/expected/test___ScheduledReports.generateReport_year.original.pdf b/plugins/CustomDimensions/tests/System/expected/test___ScheduledReports.generateReport_year.original.pdf index e0763866aab..56d5f6ac1a9 100644 Binary files a/plugins/CustomDimensions/tests/System/expected/test___ScheduledReports.generateReport_year.original.pdf and b/plugins/CustomDimensions/tests/System/expected/test___ScheduledReports.generateReport_year.original.pdf differ diff --git a/plugins/Ecommerce/tests/System/expected/test_ecommerceOrderWithItems_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf b/plugins/Ecommerce/tests/System/expected/test_ecommerceOrderWithItems_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf index 8d16ba30451..65fed28ac1b 100644 Binary files a/plugins/Ecommerce/tests/System/expected/test_ecommerceOrderWithItems_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf and b/plugins/Ecommerce/tests/System/expected/test_ecommerceOrderWithItems_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf differ diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf index 8adcce11f11..f7de19c34fa 100644 Binary files a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf and b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_schedrep_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf differ