Release 2.33.0 (#5438)

This commit is contained in:
Kevin Papst
2025-04-22 20:43:22 +02:00
committed by GitHub
parent a70c803158
commit e663cc2b02
58 changed files with 1404 additions and 899 deletions

View File

@@ -12,6 +12,7 @@ namespace App\Export\Base;
use App\Entity\ExportableItem;
use App\Export\ExportFilename;
use App\Export\Package\CellFormatter\DateStringFormatter;
use App\Export\Package\CellFormatter\DurationPlainFormatter;
use App\Export\Package\SpoutSpreadsheet;
use App\Export\RendererInterface;
use App\Export\TimesheetExportInterface;
@@ -71,6 +72,7 @@ final class CsvRenderer implements RendererInterface, TimesheetExportInterface
$spreadsheet->open($filename);
$this->spreadsheetRenderer->registerFormatter('date', new DateStringFormatter());
$this->spreadsheetRenderer->registerFormatter('duration', new DurationPlainFormatter());
$this->spreadsheetRenderer->writeSpreadsheet($spreadsheet, $exportItems, $query);
return new \SplFileInfo($filename);

View File

@@ -105,7 +105,7 @@ final class SpreadsheetRenderer
$formula = null;
if (\in_array($column->getName(), $totalColumns)) {
$columnName = $columnNames[$totalColumn - 1];
$formula = \sprintf('=SUM(%s2:%s%s)', $columnName, $columnName, $currentRow);
$formula = \sprintf('=SUBTOTAL(9,%s2:%s%s)', $columnName, $columnName, $currentRow);
}
$totalRow[] = $formula;
$totalColumn++;

View File

@@ -0,0 +1,15 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Export\Package\CellFormatter;
interface CellWithFormatInterface
{
public function getFormat(): string;
}

View File

@@ -9,7 +9,7 @@
namespace App\Export\Package\CellFormatter;
final class DateFormatter implements CellFormatterInterface
final class DateFormatter implements CellFormatterInterface, CellWithFormatInterface
{
public function formatValue(mixed $value): mixed
{
@@ -23,4 +23,9 @@ final class DateFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Only DateTimeInterface can be formatted');
}
public function getFormat(): string
{
return 'yyyy-mm-dd';
}
}

View File

@@ -9,23 +9,34 @@
namespace App\Export\Package\CellFormatter;
use App\Utils\Duration;
final class DurationFormatter implements CellFormatterInterface
final class DurationFormatter implements CellFormatterInterface, CellWithFormatInterface
{
private Duration $duration;
public function __construct()
{
$this->duration = new Duration();
}
public function formatValue(mixed $value): mixed
{
if (is_numeric($value)) {
return $this->duration->format((int) $value);
if (!is_numeric($value) || (int) $value === 0) {
return new \DateInterval('PT0S');
}
return $this->duration->format(0);
$value = (int) $value;
$seconds = abs($value);
$hours = intdiv($seconds, 3600);
$seconds %= 3600;
$minutes = intdiv($seconds, 60);
$seconds %= 60;
$intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds);
$interval = new \DateInterval($intervalSpec);
if ($value < 0) {
$interval->invert = 1;
}
return $interval;
}
public function getFormat(): string
{
return '[hh]:mm:ss';
}
}

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Export\Package\CellFormatter;
final class DurationPlainFormatter implements CellFormatterInterface
{
public function formatValue(mixed $value): mixed
{
if (!is_numeric($value) || (int) $value === 0) {
return '0:00:00';
}
$value = (int) $value;
$seconds = abs($value);
$hours = intdiv($seconds, 3600);
$seconds %= 3600;
$minutes = intdiv($seconds, 60);
$seconds %= 60;
$intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds);
$interval = new \DateInterval($intervalSpec);
if ($value < 0) {
$interval->invert = 1;
}
return $interval->format('%r%h:%I:%S');
}
}

View File

@@ -11,6 +11,7 @@ namespace App\Export\Package;
use App\Entity\ExportableItem;
use App\Export\Package\CellFormatter\CellFormatterInterface;
use App\Export\Package\CellFormatter\CellWithFormatInterface;
class Column
{
@@ -71,4 +72,13 @@ class Column
{
return $this->header ?? $this->name;
}
public function getFormat(): ?string
{
if ($this->formatter instanceof CellWithFormatInterface) {
return $this->formatter->getFormat();
}
return null;
}
}

View File

@@ -26,7 +26,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class SpoutSpreadsheet implements SpreadsheetPackage
{
private Style $dateStyle;
/** @var array<int, Style|null> */
private array $styles = [];
public function __construct(
private readonly WriterInterface $writer,
@@ -34,7 +35,6 @@ class SpoutSpreadsheet implements SpreadsheetPackage
)
{
$this->writer->setCreator(Constants::SOFTWARE);
$this->dateStyle = (new Style())->setFormat('yyyy-mm-dd');
}
/**
@@ -48,9 +48,15 @@ class SpoutSpreadsheet implements SpreadsheetPackage
}
$tmp = [];
$i = 0;
foreach ($columns as $column) {
$title = $this->translator->trans($column->getHeader());
$tmp[] = Cell::fromValue($title);
$style = null;
if ($column->getFormat() !== null) {
$style = (new Style())->setFormat($column->getFormat());
}
$this->styles[$i++] = $style;
}
$style = new Style();
@@ -100,12 +106,9 @@ class SpoutSpreadsheet implements SpreadsheetPackage
}
$tmp = [];
$i = 0;
foreach ($columns as $column) {
if ($column instanceof \DateTimeInterface) {
$tmp[] = Cell::fromValue($column, $this->dateStyle);
} else {
$tmp[] = Cell::fromValue($column); // @phpstan-ignore argument.type
}
$tmp[] = Cell::fromValue($column, $this->styles[$i++]); // @phpstan-ignore argument.type
}
$this->writer->addRow(new Row($tmp, $style));