Add report exports

This commit is contained in:
Constantin Graf
2024-10-25 16:37:40 +02:00
committed by Constantin Graf
parent 7c1fe35754
commit 8712cfb9dc
16 changed files with 924 additions and 82 deletions

View File

@@ -36,6 +36,8 @@ abstract class CsvExport
private string $folderPath;
protected const string CARBON_FORMAT = 'Y-m-d\TH:i:sP';
/**
* @param Builder<T> $builder
*/
@@ -51,7 +53,7 @@ abstract class CsvExport
/**
* @param T $model
* @return array<string, string|Carbon|null>
* @return array<string, string|float|Carbon|null>
*/
abstract public function mapRow(Model $model): array;
@@ -83,7 +85,7 @@ abstract class CsvExport
}
/**
* @param array<string, string|Carbon|null> $data
* @param array<string, string|float|Carbon|null> $data
* @return array<string, string>
*/
private function convertRow(array $data): array
@@ -91,7 +93,9 @@ abstract class CsvExport
$convertedRow = [];
foreach ($data as $key => $value) {
if ($value instanceof Carbon) {
$convertedRow[$key] = $value->toIso8601String();
$convertedRow[$key] = $value->format(static::CARBON_FORMAT);
} elseif (is_float($value)) {
$convertedRow[$key] = (string) $value;
} elseif ($value === null) {
$convertedRow[$key] = '';
} else {

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Service\ReportExport;
use App\Models\TimeEntry;
use App\Service\IntervalService;
use Illuminate\Database\Eloquent\Model;
/**
@@ -26,11 +27,14 @@ class TimeEntriesDetailedCsvExport extends CsvExport
'Tags',
];
protected const string CARBON_FORMAT = 'Y-m-d H:i:s';
/**
* @param TimeEntry $model
*/
public function mapRow(Model $model): array
{
$interval = app(IntervalService::class);
$duration = $model->getDuration();
return [
@@ -39,9 +43,9 @@ class TimeEntriesDetailedCsvExport extends CsvExport
'Project' => $model->project?->name,
'Client' => $model->client?->name,
'User' => $model->user->name,
'Start' => $model->start->format('Y-m-d H:i:s'),
'End' => $model->end?->format('Y-m-d H:i:s'),
'Duration' => $duration !== null ? (int) floor($duration->totalHours).':'.$duration->format('%I:%S') : null,
'Start' => $model->start,
'End' => $model->end,
'Duration' => $duration !== null ? $interval->format($model->getDuration()) : null,
'Duration (decimal)' => $duration?->totalHours,
'Billable' => $model->billable ? 'Yes' : 'No',
'Tags' => $model->tagsRelation->pluck('name')->implode(', '),

View File

@@ -6,13 +6,13 @@ namespace App\Service\ReportExport;
use App\Enums\ExportFormat;
use App\Models\TimeEntry;
use App\Service\IntervalService;
use Illuminate\Database\Eloquent\Builder;
use LogicException;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
@@ -24,7 +24,7 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
/**
* @implements WithMapping<TimeEntry>
*/
class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, WithColumnFormatting, WithDefaultStyles, WithHeadings, WithMapping, WithStyles
class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, WithColumnFormatting, WithHeadings, WithMapping, WithStyles
{
use Exportable;
@@ -52,6 +52,9 @@ class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, WithColumn
return $this->builder;
}
/**
* @return array<string, string>
*/
public function columnFormats(): array
{
if ($this->exportFormat === ExportFormat::XLSX) {
@@ -81,12 +84,6 @@ class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, WithColumn
];
}
public function defaultStyles(Style $defaultStyle)
{
// Configure the default styles
return $defaultStyle->getFill(); //->setFillType(Fill::FILL_SOLID);
}
/**
* @return string[]
*/
@@ -113,6 +110,7 @@ class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, WithColumn
*/
public function map($model): array
{
$interval = app(IntervalService::class);
$duration = $model->getDuration();
if ($this->exportFormat === ExportFormat::XLSX) {
@@ -124,7 +122,7 @@ class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, WithColumn
$model->user->name,
Date::dateTimeToExcel($model->start),
$model->end !== null ? Date::dateTimeToExcel($model->end) : null,
$duration !== null ? (int) floor($duration->totalHours).':'.$duration->format('%I:%S') : null,
$duration !== null ? $interval->format($duration) : null,
$duration?->totalHours,
$model->billable ? 'Yes' : 'No',
$model->tagsRelation->pluck('name')->implode(', '),

View File

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace App\Service\ReportExport;
use App\Enums\ExportFormat;
use App\Enums\TimeEntryAggregationType;
use Illuminate\View\View;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromView;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
class TimeEntriesReportExport implements FromView, ShouldAutoSize, WithCustomCsvSettings
{
use Exportable;
/**
* @var array{
* grouped_type: string|null,
* grouped_data: null|array<array{
* key: string|null,
* seconds: int,
* cost: int,
* grouped_type: string|null,
* grouped_data: null|array<array{
* key: string|null,
* seconds: int,
* cost: int,
* grouped_type: null,
* grouped_data: null
* }>
* }>,
* seconds: int,
* cost: int
* }
*/
private array $data;
private ExportFormat $exportFormat;
private string $currency;
private TimeEntryAggregationType $group;
private TimeEntryAggregationType $subGroup;
/**
* @param array{
* grouped_type: string|null,
* grouped_data: null|array<array{
* key: string|null,
* seconds: int,
* cost: int,
* grouped_type: string|null,
* grouped_data: null|array<array{
* key: string|null,
* seconds: int,
* cost: int,
* grouped_type: null,
* grouped_data: null
* }>
* }>,
* seconds: int,
* cost: int
* } $data
*/
public function __construct(array $data, ExportFormat $exportFormat, string $currency, TimeEntryAggregationType $group, TimeEntryAggregationType $subGroup)
{
$this->data = $data;
$this->exportFormat = $exportFormat;
$this->currency = $currency;
$this->group = $group;
$this->subGroup = $subGroup;
}
public function view(): View
{
return view('reports.time-entry-aggregate-index-excel', [
'data' => $this->data,
'currency' => $this->currency,
'group' => $this->group,
'subGroup' => $this->subGroup,
'exportFormat' => $this->exportFormat,
]);
}
/**
* @return array<string, string>
*/
public function getCsvSettings(): array
{
return [
'delimiter' => ',',
'enclosure' => '"',
'escape_character' => '',
];
}
}