Files
construprogress/app/Jobs/CaptureDailyProgressSnapshot.php
T
Javier Braña 90630379fb chore: cleanup dead code + format with Pint
- Remove unused FeaturesController (empty stubs, no routes)
- Remove ConvertSpatialFile CLI command (unused; service used in LayerManager)
- Remove MigrateGeojsonToFeatures CLI command (one-shot migration, not referenced)
- Remove .claude/worktrees/ (11 old agent worktrees from June)
- Apply Laravel Pint formatting across 219 files (style only, no functional changes)

Tests: 101 passing (319 assertions)
API routes: unchanged (8 routes intact)
2026-08-28 13:04:28 +02:00

175 lines
6.0 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\Feature;
use App\Models\Phase;
use App\Models\ProgressSnapshot;
use App\Models\Task;
use Carbon\Carbon;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;
class CaptureDailyProgressSnapshot implements ShouldQueue
{
use Queueable;
public function __construct(
public ?string $snapshotDate = null
) {}
public function handle(): void
{
$date = $this->snapshotDate ? Carbon::parse($this->snapshotDate) : Carbon::today();
Log::info('Starting daily progress snapshot capture', ['date' => $date->toDateString()]);
$captured = 0;
// Capture Phase snapshots
$captured += $this->capturePhaseSnapshots($date);
// Capture Feature snapshots
$captured += $this->captureFeatureSnapshots($date);
// Capture Task snapshots
$captured += $this->captureTaskSnapshots($date);
Log::info('Daily progress snapshot capture completed', [
'date' => $date->toDateString(),
'snapshots_captured' => $captured,
]);
}
private function capturePhaseSnapshots(Carbon $date): int
{
$count = 0;
Phase::with(['project'])->chunkById(100, function ($phases) use ($date, &$count) {
foreach ($phases as $phase) {
// Skip if snapshot already exists for this date
if (ProgressSnapshot::where('trackable_type', Phase::class)
->where('trackable_id', $phase->id)
->where('snapshot_date', $date)
->exists()) {
continue;
}
$metadata = [
'project_id' => $phase->project_id,
'spi' => $phase->spi,
'is_on_track' => $phase->is_on_track,
'deviation_days' => $phase->deviation_days,
'start_deviation_days' => $phase->start_deviation_days,
];
ProgressSnapshot::create([
'trackable_type' => Phase::class,
'trackable_id' => $phase->id,
'snapshot_date' => $date,
'progress' => $phase->progress_percent,
'planned_start' => $phase->planned_start,
'planned_end' => $phase->planned_end,
'actual_start' => $phase->actual_start,
'actual_end' => $phase->actual_end,
'method' => 'manual',
'metadata' => $metadata,
]);
$count++;
}
});
return $count;
}
private function captureFeatureSnapshots(Carbon $date): int
{
$count = 0;
Feature::with(['layer.phase.project'])->chunkById(200, function ($features) use ($date, &$count) {
foreach ($features as $feature) {
if (ProgressSnapshot::where('trackable_type', Feature::class)
->where('trackable_id', $feature->id)
->where('snapshot_date', $date)
->exists()) {
continue;
}
$metadata = [
'project_id' => $feature->layer->phase->project_id ?? null,
'phase_id' => $feature->layer->phase_id ?? null,
'layer_id' => $feature->layer_id,
'spi' => $feature->spi,
'is_on_track' => $feature->is_on_track,
'deviation_days' => $feature->deviation_days,
'start_deviation_days' => $feature->start_deviation_days,
'status' => $feature->status,
];
ProgressSnapshot::create([
'trackable_type' => Feature::class,
'trackable_id' => $feature->id,
'snapshot_date' => $date,
'progress' => $feature->progress,
'planned_start' => $feature->planned_start,
'planned_end' => $feature->planned_end,
'actual_start' => $feature->actual_start,
'actual_end' => $feature->actual_end,
'method' => 'manual',
'metadata' => $metadata,
]);
$count++;
}
});
return $count;
}
private function captureTaskSnapshots(Carbon $date): int
{
$count = 0;
Task::with(['project', 'phase'])->chunkById(200, function ($tasks) use ($date, &$count) {
foreach ($tasks as $task) {
if (ProgressSnapshot::where('trackable_type', Task::class)
->where('trackable_id', $task->id)
->where('snapshot_date', $date)
->exists()) {
continue;
}
$metadata = [
'project_id' => $task->project_id,
'phase_id' => $task->phase_id,
'status' => $task->status,
'priority' => $task->priority,
'assigned_to' => $task->assigned_to,
'is_overdue' => $task->is_overdue,
'estimated_hours' => $task->estimated_hours,
'actual_hours' => $task->actual_hours,
];
ProgressSnapshot::create([
'trackable_type' => Task::class,
'trackable_id' => $task->id,
'snapshot_date' => $date,
'progress' => $task->progress,
'planned_start' => $task->start_date,
'planned_end' => $task->due_date,
'actual_start' => $task->start_date,
'actual_end' => $task->completed_at?->toDateString(),
'method' => 'task',
'metadata' => $metadata,
]);
$count++;
}
});
return $count;
}
}