HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux Bradford-Sitios 6.14.0-1017-azure #17~24.04.1-Ubuntu SMP Mon Dec 1 20:10:50 UTC 2025 x86_64
User: www-data (33)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/api-talleres.bradford/app/Models/ExcelUpload.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class ExcelUpload extends Model
{

    protected $table = 'excel_uploads';

    protected $fillable = [
        'type',
        'file_name',
        'file_path',
        'original_name',
        'file_size',
        'status',
        'total_rows',
        'success_rows',
        'error_rows',
        'warning_rows',
        'uploaded_by',
        'uploaded_at',
        'processed_at',
        'confirmed_at',
        'notes',
        'metadata',
    ];

    protected $casts = [
        'metadata' => 'array',
        'uploaded_at' => 'datetime',
        'processed_at' => 'datetime',
        'confirmed_at' => 'datetime',
        'file_size' => 'integer',
        'total_rows' => 'integer',
        'success_rows' => 'integer',
        'error_rows' => 'integer',
        'warning_rows' => 'integer',
    ];

    /**
     * Relación con líneas del upload
     */
    public function lines(): HasMany
    {
        return $this->hasMany(ExcelUploadLine::class, 'upload_id');
    }

    /**
     * Usuario que subió el archivo
     */
    public function uploadedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'uploaded_by');
    }

    /**
     * Logs del upload
     */
    public function logs(): HasMany
    {
        return $this->hasMany(ExcelUploadLog::class, 'upload_id');
    }

    /**
     * Tipo de upload
     */
    public function uploadType(): BelongsTo
    {
        return $this->belongsTo(ExcelUploadType::class, 'type', 'code');
    }

    /**
     * Scopes
     */
    public function scopeByType($query, string $type)
    {
        return $query->where('type', $type);
    }

    public function scopeByStatus($query, string $status)
    {
        return $query->where('status', $status);
    }

    public function scopePending($query)
    {
        return $query->where('status', 'PENDING');
    }

    public function scopeProcessing($query)
    {
        return $query->where('status', 'PROCESSING');
    }

    public function scopePendingConfirmation($query)
    {
        return $query->where('status', 'PENDING_CONFIRMATION');
    }

    public function scopeCompleted($query)
    {
        return $query->where('status', 'COMPLETED');
    }

    public function scopeWithErrors($query)
    {
        return $query->where('error_rows', '>', 0);
    }

    public function scopeRecent($query, int $days = 30)
    {
        return $query->where('uploaded_at', '>=', now()->subDays($days));
    }

    /**
     * Verificaciones de estado
     */
    public function isPending(): bool
    {
        return $this->status === 'PENDING';
    }

    public function isProcessing(): bool
    {
        return $this->status === 'PROCESSING';
    }

    public function isPendingConfirmation(): bool
    {
        return $this->status === 'PENDING_CONFIRMATION';
    }

    public function isCompleted(): bool
    {
        return $this->status === 'COMPLETED';
    }

    public function hasErrors(): bool
    {
        return $this->error_rows > 0;
    }

    public function hasWarnings(): bool
    {
        return $this->warning_rows > 0;
    }

    public function canBeConfirmed(): bool
    {
        return $this->isPendingConfirmation() && !$this->hasErrors();
    }

    /**
     * Cambios de estado
     */
    public function markAsProcessing(): void
    {
        $this->update([
            'status' => 'PROCESSING',
            'processed_at' => now(),
        ]);
    }

    public function markAsPendingConfirmation(): void
    {
        $this->update(['status' => 'PENDING_CONFIRMATION']);
    }

    public function markAsCompleted(): void
    {
        $this->update([
            'status' => 'COMPLETED',
            'confirmed_at' => now(),
        ]);
    }

    public function markAsError(string $message = ''): void
    {
        $this->update([
            'status' => 'ERROR',
            'notes' => $message,
        ]);
    }

    /**
     * Actualizar contadores
     */
    public function updateCounters(): void
    {
        $this->update([
            'total_rows' => $this->lines()->count(),
            'success_rows' => $this->lines()->where('status', 'SUCCESS')->count(),
            'error_rows' => $this->lines()->where('status', 'ERROR')->count(),
            'warning_rows' => $this->lines()->where('status', 'WARNING')->count(),
        ]);
    }

    /**
     * Obtener porcentaje de éxito
     */
    public function getSuccessPercentage(): float
    {
        if ($this->total_rows === 0) {
            return 0;
        }

        return round(($this->success_rows / $this->total_rows) * 100, 2);
    }

    /**
     * Obtener tamaño del archivo formateado
     */
    public function getFormattedFileSize(): string
    {
        $bytes = $this->file_size;
        
        if ($bytes >= 1048576) {
            return round($bytes / 1048576, 2) . ' MB';
        } elseif ($bytes >= 1024) {
            return round($bytes / 1024, 2) . ' KB';
        }
        
        return $bytes . ' bytes';
    }

    /**
     * Obtener ruta completa del archivo
     */
    public function getFullFilePath(): string
    {
        return storage_path("app/{$this->file_path}");
    }

    /**
     * Verificar si el archivo existe
     */
    public function fileExists(): bool
    {
        return file_exists($this->getFullFilePath());
    }

    /**
     * Eliminar archivo físico
     */
    public function deleteFile(): bool
    {
        if ($this->fileExists()) {
            return unlink($this->getFullFilePath());
        }
        
        return false;
    }
}