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)
This commit is contained in:
Javier Braña
2026-08-28 13:04:28 +02:00
parent 2dccd59385
commit 90630379fb
139 changed files with 2888 additions and 2510 deletions
+5 -5
View File
@@ -12,18 +12,18 @@ class ActivityLog extends Model
protected $fillable = ['action', 'model_type', 'model_id', 'user_id', 'changes', 'created_at'];
protected $casts = [
'changes' => 'array',
'changes' => 'array',
'created_at' => 'datetime',
];
public static function record(string $action, Model $model, array $changes = []): void
{
static::create([
'action' => $action,
'action' => $action,
'model_type' => class_basename($model),
'model_id' => $model->getKey(),
'user_id' => Auth::id(),
'changes' => empty($changes) ? null : $changes,
'model_id' => $model->getKey(),
'user_id' => Auth::id(),
'changes' => empty($changes) ? null : $changes,
'created_at' => now(),
]);
}
+2 -3
View File
@@ -2,7 +2,6 @@
namespace App\Models;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@@ -35,7 +34,7 @@ class Company extends Model
public function projects()
{
return $this->belongsToMany(Project::class, 'company_project')
->withPivot('role_in_project')
->withTimestamps();
->withPivot('role_in_project')
->withTimestamps();
}
}
+28 -26
View File
@@ -2,14 +2,15 @@
namespace App\Models;
use App\Traits\LogsActivity;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Traits\LogsActivity;
class Feature extends Model
{
use SoftDeletes, LogsActivity;
use LogsActivity, SoftDeletes;
const STATUSES = ['planned', 'started', 'in_progress', 'completed', 'verified'];
@@ -22,15 +23,15 @@ class Feature extends Model
];
protected $casts = [
'geometry' => 'array',
'properties' => 'array',
'is_active' => 'boolean',
'planned_start' => 'date',
'planned_end' => 'date',
'actual_start' => 'date',
'actual_end' => 'date',
'baseline_start' => 'date',
'baseline_end' => 'date',
'geometry' => 'array',
'properties' => 'array',
'is_active' => 'boolean',
'planned_start' => 'date',
'planned_end' => 'date',
'actual_start' => 'date',
'actual_end' => 'date',
'baseline_start' => 'date',
'baseline_end' => 'date',
];
public function featureType()
@@ -80,13 +81,13 @@ class Feature extends Model
public function getStatusColorAttribute(): string
{
return match($this->status) {
'planned' => '#6b7280',
'started' => '#3b82f6',
return match ($this->status) {
'planned' => '#6b7280',
'started' => '#3b82f6',
'in_progress' => '#f59e0b',
'completed' => '#10b981',
'verified' => '#8b5cf6',
default => '#6b7280',
'completed' => '#10b981',
'verified' => '#8b5cf6',
default => '#6b7280',
};
}
@@ -99,7 +100,7 @@ class Feature extends Model
return null;
}
$end = $this->actual_end ?? now()->toDateString();
return $this->planned_end->diffInDays($end, false);
}
@@ -109,28 +110,28 @@ class Feature extends Model
return null;
}
$start = $this->actual_start ?? now()->toDateString();
return $this->planned_start->diffInDays($start, false);
}
public function getPlannedProgressAtAttribute(?\Carbon\Carbon $date = null): float
public function getPlannedProgressAtAttribute(?Carbon $date = null): float
{
$date = $date ?? now();
if (! $this->planned_start || ! $this->planned_end) {
return 0;
}
if ($date <= $this->planned_start) {
return 0;
}
if ($date >= $this->planned_end) {
return 100;
}
$totalDays = $this->planned_start->diffInDays($this->planned_end);
$elapsedDays = $this->planned_start->diffInDays($date);
return round(($elapsedDays / $totalDays) * 100, 2);
}
@@ -138,11 +139,11 @@ class Feature extends Model
{
$pv = $this->planned_progress_at;
$ev = $this->progress;
if ($pv <= 0) {
return null;
}
return round($ev / $pv, 2);
}
@@ -152,6 +153,7 @@ class Feature extends Model
if ($spi === null) {
return null;
}
return $spi >= 0.95;
}
}
+19 -7
View File
@@ -2,13 +2,13 @@
namespace App\Models;
use App\Traits\LogsActivity;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Traits\LogsActivity;
class Inspection extends Model
{
use SoftDeletes, LogsActivity;
use LogsActivity, SoftDeletes;
protected static function booted(): void
{
@@ -19,7 +19,8 @@ class Inspection extends Model
}
const STATUSES = ['pending', 'in_progress', 'completed', 'approved', 'rejected'];
const RESULTS = ['pass', 'fail', 'conditional'];
const RESULTS = ['pass', 'fail', 'conditional'];
protected $fillable = [
'project_id', 'layer_id', 'feature_id', 'template_id', 'user_id',
@@ -28,7 +29,7 @@ class Inspection extends Model
];
protected $casts = [
'data' => 'array',
'data' => 'array',
'completed_at' => 'datetime',
];
@@ -72,7 +73,18 @@ class Inspection extends Model
return $this->hasMany(Issue::class);
}
public function scopePending($q) { return $q->where('status', 'pending'); }
public function scopeCompleted($q) { return $q->where('status', 'completed'); }
public function scopeRejected($q) { return $q->where('status', 'rejected'); }
public function scopePending($q)
{
return $q->where('status', 'pending');
}
public function scopeCompleted($q)
{
return $q->where('status', 'completed');
}
public function scopeRejected($q)
{
return $q->where('status', 'rejected');
}
}
+74 -33
View File
@@ -2,17 +2,19 @@
namespace App\Models;
use App\Traits\LogsActivity;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Traits\LogsActivity;
class Issue extends Model
{
use SoftDeletes, LogsActivity;
use LogsActivity, SoftDeletes;
const STATUSES = ['open', 'in_review', 'resolved', 'closed'];
const STATUSES = ['open', 'in_review', 'resolved', 'closed'];
const PRIORITIES = ['low', 'medium', 'high', 'critical'];
const TYPES = ['defect', 'safety', 'quality', 'documentation', 'other'];
const TYPES = ['defect', 'safety', 'quality', 'documentation', 'other'];
protected $fillable = [
'project_id', 'feature_id', 'inspection_id',
@@ -23,17 +25,55 @@ class Issue extends Model
protected $casts = ['resolved_at' => 'datetime'];
public function project() { return $this->belongsTo(Project::class); }
public function feature() { return $this->belongsTo(Feature::class); }
public function inspection() { return $this->belongsTo(Inspection::class); }
public function reporter() { return $this->belongsTo(User::class, 'reported_by'); }
public function assignee() { return $this->belongsTo(User::class, 'assigned_to'); }
public function media() { return $this->morphMany(Media::class, 'mediable'); }
public function tasks() { return $this->hasMany(IssueTask::class)->orderBy('order')->orderBy('id'); }
public function comments() { return $this->hasMany(IssueComment::class)->orderBy('created_at'); }
public function project()
{
return $this->belongsTo(Project::class);
}
public function scopeOpen($q) { return $q->where('status', 'open'); }
public function scopeCritical($q) { return $q->where('priority', 'critical'); }
public function feature()
{
return $this->belongsTo(Feature::class);
}
public function inspection()
{
return $this->belongsTo(Inspection::class);
}
public function reporter()
{
return $this->belongsTo(User::class, 'reported_by');
}
public function assignee()
{
return $this->belongsTo(User::class, 'assigned_to');
}
public function media()
{
return $this->morphMany(Media::class, 'mediable');
}
public function tasks()
{
return $this->hasMany(IssueTask::class)->orderBy('order')->orderBy('id');
}
public function comments()
{
return $this->hasMany(IssueComment::class)->orderBy('created_at');
}
public function scopeOpen($q)
{
return $q->where('status', 'open');
}
public function scopeCritical($q)
{
return $q->where('priority', 'critical');
}
/** Resolution progress derived from the checklist: done tasks / total. */
public function getProgressAttribute(): int
@@ -42,6 +82,7 @@ class Issue extends Model
if ($total === 0) {
return in_array($this->status, ['resolved', 'closed'], true) ? 100 : 0;
}
return (int) round($this->tasks->where('is_done', true)->count() / $total * 100);
}
@@ -53,23 +94,23 @@ class Issue extends Model
public function getPriorityColorAttribute(): string
{
return match($this->priority) {
'low' => '#6b7280',
'medium' => '#f59e0b',
'high' => '#ef4444',
return match ($this->priority) {
'low' => '#6b7280',
'medium' => '#f59e0b',
'high' => '#ef4444',
'critical' => '#7c3aed',
default => '#6b7280',
default => '#6b7280',
};
}
public function getStatusColorAttribute(): string
{
return match($this->status) {
'open' => '#ef4444',
return match ($this->status) {
'open' => '#ef4444',
'in_review' => '#f59e0b',
'resolved' => '#10b981',
'closed' => '#6b7280',
default => '#6b7280',
'resolved' => '#10b981',
'closed' => '#6b7280',
default => '#6b7280',
};
}
@@ -77,11 +118,11 @@ class Issue extends Model
public static function typeLabels(): array
{
return [
'defect' => 'Defecto',
'safety' => 'Seguridad',
'quality' => 'Calidad',
'defect' => 'Defecto',
'safety' => 'Seguridad',
'quality' => 'Calidad',
'documentation' => 'Documentación',
'other' => 'Otro',
'other' => 'Otro',
];
}
@@ -92,12 +133,12 @@ class Issue extends Model
public function getTypeColorAttribute(): string
{
return match($this->type) {
'defect' => '#ef4444',
'safety' => '#f97316',
'quality' => '#0ea5e9',
return match ($this->type) {
'defect' => '#ef4444',
'safety' => '#f97316',
'quality' => '#0ea5e9',
'documentation' => '#8b5cf6',
default => '#6b7280',
default => '#6b7280',
};
}
}
+14 -3
View File
@@ -14,7 +14,18 @@ class IssueComment extends Model
'uuid', 'client_updated_at',
];
public function issue() { return $this->belongsTo(Issue::class); }
public function user() { return $this->belongsTo(User::class); }
public function media() { return $this->morphMany(Media::class, 'mediable'); }
public function issue()
{
return $this->belongsTo(Issue::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function media()
{
return $this->morphMany(Media::class, 'mediable');
}
}
+24 -9
View File
@@ -16,9 +16,9 @@ class IssueTask extends Model
];
protected $casts = [
'is_done' => 'boolean',
'done_at' => 'datetime',
'due_date' => 'date',
'is_done' => 'boolean',
'done_at' => 'datetime',
'due_date' => 'date',
'overdue_notified_at' => 'datetime',
];
@@ -26,14 +26,29 @@ class IssueTask extends Model
public function scopeOverdue($q)
{
return $q->where('is_done', false)
->whereNotNull('due_date')
->whereDate('due_date', '<', now()->toDateString());
->whereNotNull('due_date')
->whereDate('due_date', '<', now()->toDateString());
}
public function issue() { return $this->belongsTo(Issue::class); }
public function assignee() { return $this->belongsTo(User::class, 'assigned_to'); }
public function completer() { return $this->belongsTo(User::class, 'done_by'); }
public function media() { return $this->morphMany(Media::class, 'mediable'); }
public function issue()
{
return $this->belongsTo(Issue::class);
}
public function assignee()
{
return $this->belongsTo(User::class, 'assigned_to');
}
public function completer()
{
return $this->belongsTo(User::class, 'done_by');
}
public function media()
{
return $this->morphMany(Media::class, 'mediable');
}
/** Overdue = has a due date in the past and not yet done. */
public function getIsOverdueAttribute(): bool
+3 -3
View File
@@ -5,13 +5,12 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Layer extends Model
{
use SoftDeletes;
protected $fillable = [
'project_id', 'phase_id', 'name', 'color', 'geojson_data', 'original_file', 'uploaded_by'
'project_id', 'phase_id', 'name', 'color', 'geojson_data', 'original_file', 'uploaded_by',
];
protected $casts = [
@@ -32,6 +31,7 @@ class Layer extends Model
{
return $this->belongsTo(User::class, 'uploaded_by');
}
public function features()
{
return $this->hasMany(Feature::class);
@@ -46,4 +46,4 @@ class Layer extends Model
{
return $this->morphMany(Media::class, 'mediable');
}
}
}
+12 -5
View File
@@ -48,10 +48,17 @@ class Media extends Model
public function getFormattedSizeAttribute()
{
$bytes = $this->file_size;
if ($bytes >= 1073741824) return round($bytes / 1073741824, 2) . ' GB';
if ($bytes >= 1048576) return round($bytes / 1048576, 1) . ' MB';
if ($bytes >= 1024) return round($bytes / 1024) . ' KB';
return $bytes . ' B';
if ($bytes >= 1073741824) {
return round($bytes / 1073741824, 2).' GB';
}
if ($bytes >= 1048576) {
return round($bytes / 1048576, 1).' MB';
}
if ($bytes >= 1024) {
return round($bytes / 1024).' KB';
}
return $bytes.' B';
}
// Scopes
@@ -72,4 +79,4 @@ class Media extends Model
Storage::delete($media->file_path);
});
}
}
}
+1 -1
View File
@@ -12,4 +12,4 @@ class PendingSync extends Model
'payload' => 'array',
'synced_at' => 'datetime',
];
}
}
+11 -9
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -79,7 +80,7 @@ class Phase extends Model
return null;
}
$end = $this->actual_end ?? now()->toDateString();
return $this->planned_end->diffInDays($end, false);
}
@@ -92,31 +93,31 @@ class Phase extends Model
return null;
}
$start = $this->actual_start ?? now()->toDateString();
return $this->planned_start->diffInDays($start, false);
}
/**
* Planned progress at a given date (linear interpolation)
*/
public function getPlannedProgressAtAttribute(?\Carbon\Carbon $date = null): float
public function getPlannedProgressAtAttribute(?Carbon $date = null): float
{
$date = $date ?? now();
if (! $this->planned_start || ! $this->planned_end) {
return 0;
}
if ($date <= $this->planned_start) {
return 0;
}
if ($date >= $this->planned_end) {
return 100;
}
$totalDays = $this->planned_start->diffInDays($this->planned_end);
$elapsedDays = $this->planned_start->diffInDays($date);
return round(($elapsedDays / $totalDays) * 100, 2);
}
@@ -127,11 +128,11 @@ class Phase extends Model
{
$pv = $this->planned_progress_at; // Planned Value
$ev = $this->progress_percent; // Earned Value (current progress)
if ($pv <= 0) {
return null;
}
return round($ev / $pv, 2);
}
@@ -144,6 +145,7 @@ class Phase extends Model
if ($spi === null) {
return null;
}
return $spi >= 0.95;
}
}
+2 -1
View File
@@ -52,6 +52,7 @@ class ProgressSnapshot extends Model
if ($id) {
$query->where('trackable_id', $id);
}
return $query;
}
@@ -76,4 +77,4 @@ class ProgressSnapshot extends Model
->get(['snapshot_date', 'progress', 'method'])
->toArray();
}
}
}
+2 -2
View File
@@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model;
class ProgressUpdate extends Model
{
protected $fillable = [
'uuid', 'phase_id', 'user_id', 'progress_percent', 'comment', 'location', 'client_updated_at'
'uuid', 'phase_id', 'user_id', 'progress_percent', 'comment', 'location', 'client_updated_at',
];
protected $casts = [
@@ -24,4 +24,4 @@ class ProgressUpdate extends Model
{
return $this->belongsTo(User::class);
}
}
}