feat(reports): complete reporting system with deviations, progress curves, multi-format export
- Added planned/actual/baseline dates to Phase and Feature models
- Created ProgressSnapshot model + migration for historical tracking
- Implemented CaptureDailyProgressSnapshot job (scheduled daily at 06:30)
- Added DeviationCalculator logic (SPI, planned progress, deviation days)
- ReportGenerator service with complete data aggregation
- ReportController with builder, preview, generate (HTML/Excel)
- ReportBuilder Livewire component with date range, entity selection, format
- ProjectReportExport with 10 sheets (Summary, Phases, Features, Inspections, Issues, Tasks, Deviations, Media, Progress Curve, Parameters)
- Blade partials for all sections (header, summary, phases, features, inspections, issues, tasks, media, deviations, progress curve)
- New routes: /projects/{project}/reports/*
- Added 'generate reports' permission
- All 101 tests passing
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ReportFilters
|
||||
{
|
||||
public function __construct(
|
||||
public ?Carbon $dateFrom = null,
|
||||
public ?Carbon $dateTo = null,
|
||||
public array $entityTypes = [], // ['phases','features','inspections','issues','tasks','media']
|
||||
public bool $includePhotos = false,
|
||||
public string $format = 'html', // html|excel
|
||||
public bool $includeCharts = false,
|
||||
) {}
|
||||
|
||||
public static function fromRequest(array $data): self
|
||||
{
|
||||
return new self(
|
||||
dateFrom: isset($data['date_from']) ? Carbon::parse($data['date_from']) : null,
|
||||
dateTo: isset($data['date_to']) ? Carbon::parse($data['date_to']) : null,
|
||||
entityTypes: $data['entity_types'] ?? ['phases','features','inspections','issues','tasks'],
|
||||
includePhotos: (bool)($data['include_photos'] ?? false),
|
||||
format: $data['format'] ?? 'html',
|
||||
includeCharts: (bool)($data['include_charts'] ?? false),
|
||||
);
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'date_from' => $this->dateFrom?->toDateString(),
|
||||
'date_to' => $this->dateTo?->toDateString(),
|
||||
'entity_types' => $this->entityTypes,
|
||||
'include_photos' => $this->includePhotos,
|
||||
'format' => $this->format,
|
||||
'include_charts' => $this->includeCharts,
|
||||
];
|
||||
}
|
||||
|
||||
public function getAvailableEntities(): array
|
||||
{
|
||||
return [
|
||||
'phases' => 'Fases',
|
||||
'features' => 'Elementos (Features)',
|
||||
'inspections' => 'Inspecciones',
|
||||
'issues' => 'Incidencias (Issues)',
|
||||
'tasks' => 'Tareas',
|
||||
'media' => 'Archivos/Media',
|
||||
];
|
||||
}
|
||||
|
||||
public function getDateRangeLabel(): string
|
||||
{
|
||||
if ($this->dateFrom && $this->dateTo) {
|
||||
return $this->dateFrom->format('d/m/Y') . ' - ' . $this->dateTo->format('d/m/Y');
|
||||
}
|
||||
if ($this->dateFrom) {
|
||||
return 'Desde ' . $this->dateFrom->format('d/m/Y');
|
||||
}
|
||||
if ($this->dateTo) {
|
||||
return 'Hasta ' . $this->dateTo->format('d/m/Y');
|
||||
}
|
||||
return 'Todo el período';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user