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/matriculas_api_dev/app/Models/ExcelUploadLine.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;

class ExcelUploadLine extends Model
{
    protected $table = 'excel_upload_lines';

    protected $fillable = [
        'upload_id',
        'line_number',
        'status',
        'data',
        'original_data',
        'error_message',
        'warning_message',
        'editable',
        'edited',
        'edited_by',
        'edited_at',
        'related_id',
        'related_type',
    ];

    protected $casts = [
        'data' => 'array',
        'original_data' => 'array',
        'editable' => 'boolean',
        'edited' => 'boolean',
        'edited_at' => 'datetime',
    ];

    /**
     * Relación con el upload principal
     */
    public function upload(): BelongsTo
    {
        return $this->belongsTo(ExcelUpload::class, 'upload_id');
    }

    /**
     * Usuario que editó la línea
     */
    public function editedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'edited_by');
    }

    /**
     * Relación polimórfica con el registro relacionado
     * (Parent, Student, Teacher, etc.)
     */
    public function related(): MorphTo
    {
        return $this->morphTo('related');
    }

    /**
     * Scope para obtener solo líneas con éxito
     */
    public function scopeSuccess($query)
    {
        return $query->where('status', 'SUCCESS');
    }

    /**
     * Scope para obtener solo líneas con error
     */
    public function scopeError($query)
    {
        return $query->where('status', 'ERROR');
    }

    /**
     * Scope para obtener solo líneas con advertencia
     */
    public function scopeWarning($query)
    {
        return $query->where('status', 'WARNING');
    }

    /**
     * Scope para obtener solo líneas editables
     */
    public function scopeEditable($query)
    {
        return $query->where('editable', true);
    }

    /**
     * Scope para obtener solo líneas editadas
     */
    public function scopeEdited($query)
    {
        return $query->where('edited', true);
    }

    /**
     * Verificar si la línea tiene errores
     */
    public function hasError(): bool
    {
        return $this->status === 'ERROR' && !empty($this->error_message);
    }

    /**
     * Verificar si la línea tiene advertencias
     */
    public function hasWarning(): bool
    {
        return $this->status === 'WARNING' && !empty($this->warning_message);
    }

    /**
     * Marcar línea como editada
     */
    public function markAsEdited(int $userId): void
    {
        $this->update([
            'edited' => true,
            'edited_by' => $userId,
            'edited_at' => now(),
        ]);
    }

    /**
     * Actualizar datos de la línea
     */
    public function updateData(array $newData, int $userId): void
    {
        // Guardar datos originales si no existen
        if (empty($this->original_data)) {
            $this->original_data = $this->data;
        }

        $this->update([
            'data' => $newData,
            'edited' => true,
            'edited_by' => $userId,
            'edited_at' => now(),
        ]);
    }

    /**
     * Cambiar estado de la línea
     */
    public function changeStatus(string $status, ?string $message = null): void
    {
        $updates = ['status' => $status];

        if ($status === 'ERROR') {
            $updates['error_message'] = $message;
            $updates['warning_message'] = null;
        } elseif ($status === 'WARNING') {
            $updates['warning_message'] = $message;
            $updates['error_message'] = null;
        } else {
            $updates['error_message'] = null;
            $updates['warning_message'] = null;
        }

        $this->update($updates);
    }

    /**
     * Vincular con un registro creado/actualizado
     */
    public function linkToRecord(Model $model): void
    {
        $this->update([
            'related_id' => $model->id,
            'related_type' => get_class($model),
        ]);
    }

    /**
     * Obtener valor de un campo específico del data
     */
    public function getDataValue(string $key, $default = null)
    {
        return $this->data[$key] ?? $default;
    }

    /**
     * Verificar si tiene cambios respecto al original (renombrado para evitar conflicto)
     */
    public function hasDataChanges(): bool
    {
        if (empty($this->original_data)) {
            return false;
        }

        return $this->data !== $this->original_data;
    }

    /**
     * Obtener diferencias entre datos originales y actuales
     */
    public function getDataDifferences(): array
    {
        if (empty($this->original_data)) {
            return [];
        }

        $differences = [];
        
        foreach ($this->data as $key => $value) {
            $originalValue = $this->original_data[$key] ?? null;
            
            if ($value !== $originalValue) {
                $differences[$key] = [
                    'original' => $originalValue,
                    'current' => $value,
                ];
            }
        }

        return $differences;
    }

    /**
     * Restaurar datos originales
     */
    public function restoreOriginalData(): void
    {
        if (!empty($this->original_data)) {
            $this->update([
                'data' => $this->original_data,
                'edited' => false,
                'edited_by' => null,
                'edited_at' => null,
            ]);
        }
    }

    /**
     * Verificar si la línea fue modificada desde su creación
     */
    public function wasEdited(): bool
    {
        return $this->edited && !empty($this->edited_at);
    }
}