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;
}
}