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:
Javier Braña
2026-08-24 12:32:08 +02:00
parent c58a49f22d
commit ee32544525
30 changed files with 3170 additions and 7 deletions
@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('phases', function (Blueprint $table) {
// actual_start and actual_end already exist
$table->date('baseline_start')->nullable()->after('actual_end');
$table->date('baseline_end')->nullable()->after('baseline_start');
});
}
public function down(): void
{
Schema::table('phases', function (Blueprint $table) {
$table->dropColumn(['baseline_start', 'baseline_end']);
});
}
};
@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('features', function (Blueprint $table) {
$table->date('planned_start')->nullable()->after('responsible');
$table->date('planned_end')->nullable()->after('planned_start');
$table->date('actual_start')->nullable()->after('planned_end');
$table->date('actual_end')->nullable()->after('actual_start');
$table->date('baseline_start')->nullable()->after('actual_end');
$table->date('baseline_end')->nullable()->after('baseline_start');
});
}
public function down(): void
{
Schema::table('features', function (Blueprint $table) {
$table->dropColumn([
'planned_start', 'planned_end',
'actual_start', 'actual_end',
'baseline_start', 'baseline_end'
]);
});
}
};
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('progress_snapshots', function (Blueprint $table) {
$table->id();
$table->morphs('trackable'); // Phase, Feature, Task
$table->date('snapshot_date');
$table->decimal('progress', 5, 2)->default(0); // 0-100
$table->date('planned_start')->nullable();
$table->date('planned_end')->nullable();
$table->date('actual_start')->nullable();
$table->date('actual_end')->nullable();
$table->string('method')->default('manual'); // manual|inspection|task|geometry|hybrid
$table->json('metadata')->nullable(); // {earned_value, planned_value, actual_cost, spi, cpi, ...}
$table->timestamps();
// Short index name for MySQL 64-char limit
$table->unique(['trackable_type', 'trackable_id', 'snapshot_date'], 'ps_trackable_date_unique');
$table->index(['trackable_type', 'trackable_id', 'snapshot_date'], 'ps_trackable_date_idx');
$table->index(['snapshot_date'], 'ps_snapshot_date_idx');
});
}
public function down(): void
{
Schema::dropIfExists('progress_snapshots');
}
};
@@ -18,7 +18,7 @@ class RolesAndPermissionsSeeder extends Seeder
// Create permissions
$permissions = [
'view projects', 'create projects', 'edit projects', 'delete projects',
'assign users', 'upload layers', 'update progress', 'view reports', 'manage all',
'assign users', 'upload layers', 'update progress', 'view reports', 'generate reports', 'manage all',
'view inspections', 'create inspections', 'edit inspections', 'delete inspections', 'manage templates',
'view tasks', 'create tasks', 'edit tasks', 'delete tasks', 'assign tasks', 'manage all tasks',
];