Carga masiva de 2 hojas de excell

Cargar 200 o 1500 datos en una tabla de nuestra base de datos, uno a uno, es una tarea un poco enredosa, si no aburrida, ya que pasamos mucho tiempo para hacerlo, pudiendo hacerlo en 2 o 3 minutos.

Aquí voy a explicar cómo insertar en la tabla de productos los productos que tengo en una hoja de Excel, y aprovechando, también insertaremos las categorías pertenecientes a los productos.

Entonces, el primer paso es preparar nuestro archivo para insertar nuestro Excel con sus datos.

Paso 1: Configuración de SweetAlert y Librerías Necesarias

Para generar una carga masiva, en este caso, de dos hojas Excel (Productos y categorías), procedemos de la siguiente forma:

1. Incluimos los CDN necesarios para la realización de nuestro proyecto, tanto los CSS como los SCRIPTS.

Aquí dejo el ejemplo de los mismos.

            

La cabecera

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>AdminTienda</title> <!-- Google Font: Source Sans Pro --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback"> <!-- Font Awesome Icons --> <link rel="stylesheet" href="plugins/fontawesome-free/css/all.min.css"> <!-- Theme style --> <link rel="stylesheet" href="dist/css/adminlte.min.css"> </head>

Los scripts

<script src="plugins/jquery/jquery.min.js"></script> <!-- Bootstrap 4 --> <script src="plugins/bootstrap/js/bootstrap.bundle.min.js"></script> <!-- AdminLTE App --> <script src="dist/js/adminlte.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>


Paso 2: Instalación de Composer y PhpSpreadsheet

  1. Descarga e instala en la computadora Composer desde getcomposer.org.
  2. ¿Cómo instalamos PhpSpreadsheet?

Pues copiamos este comando composer require phpoffice/phpspreadsheet, luego vamos a nuestro proyecto, abrimos la terminal, nos ubicamos en nuestro proyecto y pegamos el trozo de código que hemos copiado anteriormente. Le damos "enter" y esperamos hasta que las dependencias de la librería PhpSpreadsheet se instalen completamente.

Si miramos nuestro proyecto, veremos que tenemos una nueva carpeta con el nombre "Vendor" y los archivos de Composer. Dentro de la carpeta "Vendor" están los archivos necesarios para hacer la carga de nuestros archivos a la base de datos.


...

Paso 3: Estructura del Proyecto

Asegúrate de que tu proyecto tenga la estructura adecuada, con la carpeta "vendor" generada por Composer.

Paso 4: Maquetación HTML

Crea la estructura HTML con un card de Bootstrap, un input de tipo file y un botón para iniciar la carga masiva:

            <div class="content-header">
    <div class="container-fluid">
        <div class="row mb-2">
            <div class="col-sm-6">
                <h1 class="m-0">carga masiva de productos</h1>
            </div><!-- /.col -->
            <div class="col-sm-6">
                <ol class="breadcrumb float-sm-right">
                    <li class="breadcrumb-item"><a href="#">Home</a></li>

                </ol>
            </div><!-- /.col -->
        </div><!-- /.row -->
    </div><!-- /.container-fluid -->
</div>
<!-- /.content-header -->
<!-- Main content -->
<div class="content">
    <div class="container-fluid">
        <div class="row">
            <div class="col">
                <div class="card card-info">
                    <div class="card-header">
                        <h3 class="card-title">Selecionar archivo de carga</h3>
                        <div class="card-tools">
                            <button type="button" class="btn btn-tool" data-card-widget="collapse">
                                <i class="fas fa-minus"></i>
                            </button>

                        </div> <!-- ./ end card-tools -->
                    </div> <!-- ./ end card-header -->
                    <div class="card-body">
                        <form action="" method="POST" enctype="multipart/form-data" id="form_cargaProductos">
                            <div class="row">
                                <div class="col-10">
                                    <input type="file" name="fileProductos" id="fileProductos" class="form-control"
                                        accept=".xls, .xlsx">
                                </div>
                                <div class="col-2">
                                    <input type="submit" value="cargar Productos" class="btn btn-primary"
                                        id="btnCargar">
                                </div>
                            </div>
                            <div class="row text-center ">
                                <div class="col-12">
                                    <img class="mx-auto" src="../img/loading.gif" id="img_carga" alt=""
                                        style="display: none;">
                                </div>
                            </div>
                        </form>


                    </div> <!-- ./ end card-body -->
                </div>
            </div>
        </div>
    </div><!-- /.container-fluid -->
</div>
          

Hay que recordar que estamos trabajando con un proyecto onde usamos un template, si lo vas a usar en codigo completo solo hay que aprovechar el formulario, que es la parque que va recoger nuestro excel


Paso 5: Script Ajax

Ahora creamos el script Ajax que va a servir para enviar los datos de la hoja al servidor y recibir la respuesta.

Aqui dejo el codigo del script

            <script>
$(document).ready(function() {

    $('#form_cargaProductos').on('submit', function(e) {
        e.preventDefault();
        //Verificar que se seleciono un archivo
        if ($('#fileProductos').get(0).files.length == 0) {

            Swal.fire({
                title: 'Error!',
                text: 'Debe selecionar un archivo excel',
                icon: 'warning',
                showConfirmButton: false,
                timer: 2500
            })

        } else {
            //Validar que el archivo sea xls o xlsx
            var extensiones_permitidas = ['.xls', 'xlsx'];
            var input_file_productos = $('#fileProductos');
            var exp_reg = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(" + extensiones_permitidas.join('|') +
                ")$");

            if (!exp_reg.test(input_file_productos.val().toLowerCase())) {

                Swal.fire({
                    title: 'Error!',
                    text: 'Debe selecionar un archivo excel',
                    icon: 'warning',
                    showConfirmButton: false,
                    timer: 2500
                })
                return false;
            }

            var datos = new FormData($('#form_cargaProductos')[0]);


            $('#btnCargar').prop("disabled", true);
            $('#img_carga').attr('style', 'display:block');

            $.ajax({
                type: "POST",
                url: "ajax/producto_cargaMasiva.php",
                data: datos,
                cache: false,
                contentType: false,
                processData: false,
                dataType: 'json',
                success: function(response) {
                    console.log(response);
                    if (response['totalCategorias'] > 0 && response['totalProductos'] > 0) {
                        Swal.fire({

                            position: 'center',
                            icon: 'success',
                            title: 'Se registraram ' + response['totalCategorias'] +
                                ' categorias ' + 'y ' + response[
                                    'totalProductos'] + 'productos correctamente',
                            showConfirmButton: false,
                            timer: 2500
                        })

                        $('#btnCargar').prop("disabled", false);
                        $('#img_carga').attr('style', 'display:none');
                    } else {
                        Swal.fire({

                            position: 'center',
                            icon: 'error',
                            title: 'Hay un error en el registro de categorias y productos',
                            showConfirmButton: false,
                            timer: 2500
                        })
                    }

                }
            });

        }
    })
})
</script>
          

Explicacion del script

Este script en jQuery está diseñado para manejar la carga masiva de productos desde un archivo Excel. Aquí está la explicación detallada:

 
    

Document Ready:

$(document).ready(function() {

Espera a que el documento HTML esté completamente cargado antes de ejecutar el script.

 
    

Evento de Envío del Formulario:

$('#form_cargaProductos').on('submit', function(e) {

Asocia la función a ejecutar cuando se envía el formulario con el id form_cargaProductos. El evento de envío se cancela inicialmente (e.preventDefault()) para controlar la carga a través de Ajax.

 
    

Verificación de Archivo Seleccionado:

if ($('#fileProductos').get(0).files.length == 0) {

Verifica si se ha seleccionado un archivo. Si no, muestra un mensaje de advertencia usando la librería SweetAlert (Swal).

 
    

Validación de Extensión del Archivo:

var extensiones_permitidas = ['.xls', 'xlsx']; var input_file_productos = $('#fileProductos'); var exp_reg = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(" + extensiones_permitidas.join('|') + ")$"); if (!exp_reg.test(input_file_productos.val().toLowerCase())) {

Verifica que el archivo seleccionado tenga una extensión permitida (.xls o .xlsx). Muestra un mensaje de advertencia si la extensión no es válida.

 
    

Preparación de Datos para Ajax:

var datos = new FormData($('#form_cargaProductos')[0]);

Crea un objeto FormData con los datos del formulario para enviarlos mediante Ajax.

 
    

Deshabilitar Botón y Mostrar Indicador de Carga:

$('#btnCargar').prop("disabled", true); $('#img_carga').attr('style', 'display:block');

Deshabilita el botón de carga y muestra un indicador de carga mientras se procesa la petición Ajax.

 
    

Envío de Datos mediante Ajax:

$.ajax({ // configuración de Ajax });

Realiza una petición Ajax para enviar los datos al servidor.

 
    

Manejo de Respuesta del Servidor:

success: function(response) {

Maneja la respuesta del servidor.

 
    

Verificación y Mensajes de SweetAlert:

if (response['totalCategorias'] > 0 && response['totalProductos'] > 0) {

Verifica si se registraron categorías y productos correctamente. Muestra un mensaje de éxito si todo está bien.

 
    } else {
        Swal.fire({
            position: 'center',
            icon: 'error',
            title: 'Hay un error en el registro de categorías y productos',
            showConfirmButton: false,
            timer: 2500
        })
    }

Muestra un mensaje de error si hay algún problema en el registro.

 
    

Restaurar Estado del Botón e Indicador de Carga:

$('#btnCargar').prop("disabled", false); $('#img_carga').attr('style', 'display:none');

Habilita nuevamente el botón de carga y oculta el indicador de carga después de procesar la respuesta del servidor.

Paso 6: Recibimiento de los datos y envío a la base de datos

En el servidor vamos a recibir los datos de las hojas de Excel y enviar esos datos a la tabla o tablas de la base de datos.

           <?php

require_once('../../vendor/autoload.php');
require_once('../../conexion.php');
use PhpOffice\PhpSpreadsheet\IOFactory;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Verificar que se ha enviado un archivo
    if (!empty($_FILES['fileProductos']['tmp_name'])) {
        $nombreArchivo = $_FILES['fileProductos']['tmp_name'];

        // Cargar el documento Excel
        $documento = IOFactory::load($nombreArchivo);

        // Acceder a la hoja de categorías
        $hojaCategorias = $documento->getSheet(1);
        // Obtener el número de filas en la hoja de categorías
        $numeroFilasCategorias = $hojaCategorias->getHighestDataRow();
        $categoriasRegistradas = 0;

        $hojaProductos = $documento->getSheetByName('Productos');
        $numeroFilasProductos = $hojaProductos->getHighestDataRow();
        $productosRegistrados = 0;

        for ($i = 2; $i <= $numeroFilasCategorias; $i++) {
            // Obtener valores de la hoja de categorías
            $categoria = $hojaCategorias->getCellByColumnAndRow(1, $i);
            $peso = $hojaCategorias->getCellByColumnAndRow(2, $i);
            $fechaActualizacion = date("Y-m-d");

            if (!empty($categoria)) {
                $sql = "INSERT INTO categorias_productos (categoria, peso, fechaActualizacion) 
                        VALUES (:categoria, :peso, :fechaActualizacion)";
                $stmt = $pdo->prepare($sql);
                $stmt->bindParam(':categoria', $categoria);
                $stmt->bindParam(':peso', $peso);
                $stmt->bindParam(':fechaActualizacion', $fechaActualizacion);

                if ($stmt->execute()) {
                    $categoriasRegistradas = $categoriasRegistradas + 1;
                } else {
                    $categoriasRegistradas = 0;
                }
            }
        }

        if ($categoriasRegistradas > 0) {
            
            for ($i = 2; $i <= $numeroFilasProductos; $i++) {
                // Obtener valores de la hoja de productos
                $codigoBarras = $hojaProductos->getCell("A" . $i);
                $categoria = BuscarIdCategoria($hojaProductos->getCell("B" . $i), $pdo);
                $producto = $hojaProductos->getCell("C" . $i);
                $precioCompra = $hojaProductos->getCell("D" . $i);
                $precioVenta = $hojaProductos->getCell("E" . $i);
                $beneficio = $hojaProductos->getCell("F" . $i)->getCalculatedValue();
                $stock = $hojaProductos->getCell("G" . $i);
                $minimoStock = $hojaProductos->getCell("H" . $i);
                $ventas = $hojaProductos->getCell("I" . $i);
                
                $fechaActualizacion = date("Y-m-d");
    
                if (!empty($codigoBarras)) {
                    $sql = "INSERT INTO productos (codigoBarras, categoria, producto, precioCompra, precioVenta, beneficio, stock, minimoStock, ventas, fechaActualizacion) 
                            VALUES (:codigoBarras, :categoria, :producto, :precioCompra, :precioVenta, :beneficio, :stock, :minimoStock, :ventas, :fechaActualizacion)";
                    $stmt = $pdo->prepare($sql);
                    $stmt->bindParam(':codigoBarras', $codigoBarras);
                    $stmt->bindParam(':categoria', $categoria);
                    $stmt->bindParam(':producto', $producto);
                    $stmt->bindParam(':precioCompra', $precioCompra);
                    $stmt->bindParam(':precioVenta', $precioVenta);
                    $stmt->bindParam(':beneficio', $beneficio);
                    $stmt->bindParam(':stock', $stock);
                    $stmt->bindParam(':minimoStock', $minimoStock);
                    $stmt->bindParam(':ventas', $ventas);
                    $stmt->bindParam(':fechaActualizacion', $fechaActualizacion);
    
                    if ($stmt->execute()) {
                        $productosRegistrados = $productosRegistrados + 1;
                    } else {
                        $productosRegistrados = 0;
                    }
                }
            }
        }

        $respuesta['totalCategorias'] = $categoriasRegistradas;
        $respuesta['totalProductos'] = $productosRegistrados;
        echo json_encode($respuesta);
    }

   
}
function BuscarIdCategoria($categoria, $pdo) {
    $sql = "SELECT idCategoria FROM categorias_productos WHERE categoria = :categoria";
    $stmt = $pdo->prepare($sql);
    $stmt->bindParam(':categoria', $categoria);
    $stmt->execute();

    // Obtener el resultado del fetch
    $resultado = $stmt->fetch(PDO::FETCH_ASSOC);

    // Retornar el valor de idCategoria o null si no se encuentra
    return ($resultado) ? $resultado['idCategoria'] : null;
}

?>
          

Explicacicon del codigo

1. Carga del Archivo Excel

El código utiliza la biblioteca PhpSpreadsheet para cargar el archivo Excel. Verifica que se haya enviado un archivo y obtiene su nombre temporal.

 
    <?php
    require_once('../../vendor/autoload.php');
    require_once('../../conexion.php');
    use PhpOffice\PhpSpreadsheet\IOFactory;

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (!empty($_FILES['fileProductos']['tmp_name'])) {
            $nombreArchivo = $_FILES['fileProductos']['tmp_name'];
            $documento = IOFactory::load($nombreArchivo);
            
    

2. Procesamiento de Categorías

Itera sobre la hoja de categorías del Excel, insertando cada categoría en la tabla 'categorias_productos' de la base de datos. La fecha de actualización se establece en el momento de la inserción.

 
    <?php
    for ($i = 2; $i <= $numeroFilasCategorias; $i++) {
        $categoria = $hojaCategorias->getCellByColumnAndRow(1, $i);
        $peso = $hojaCategorias->getCellByColumnAndRow(2, $i);
        $fechaActualizacion = date("Y-m-d");

        if (!empty($categoria)) {
            $sql = "INSERT INTO categorias_productos (categoria, peso, fechaActualizacion) 
                    VALUES (:categoria, :peso, :fechaActualizacion)";
            $stmt = $pdo->prepare($sql);
            $stmt->bindParam(':categoria', $categoria);
            $stmt->bindParam(':peso', $peso);
            $stmt->bindParam(':fechaActualizacion', $fechaActualizacion);

            if ($stmt->execute()) {
                $categoriasRegistradas = $categoriasRegistradas + 1;
            } else {
                $categoriasRegistradas = 0;
            }
        }
    }
    ? >
    

3. Procesamiento de Productos

Similar al paso anterior, itera sobre la hoja de productos y realiza la inserción en la tabla 'productos'. Busca el ID de la categoría correspondiente utilizando la función BuscarIdCategoria.

 
    <?php
    for ($i = 2; $i <= $numeroFilasProductos; $i++) {
        $codigoBarras = $hojaProductos->getCell("A" . $i);
        $categoria = BuscarIdCategoria($hojaProductos->getCell("B" . $i), $pdo);
        $producto = $hojaProductos->getCell("C" . $i);
        $precioCompra = $hojaProductos->getCell("D" . $i);
        $precioVenta = $hojaProductos->getCell("E" . $i);
        $beneficio = $hojaProductos->getCell("F" . $i)->getCalculatedValue();
        $stock = $hojaProductos->getCell("G" . $i);
        $minimoStock = $hojaProductos->getCell("H" . $i);
        $ventas = $hojaProductos->getCell("I" . $i);
        $fechaActualizacion = date("Y-m-d");

        if (!empty($codigoBarras)) {
            $sql = "INSERT INTO productos (codigoBarras, categoria, producto, precioCompra, precioVenta, beneficio, stock, minimoStock, ventas, fechaActualizacion) 
                    VALUES (:codigoBarras, :categoria, :producto, :precioCompra, :precioVenta, :beneficio, :stock, :minimoStock, :ventas, :fechaActualizacion)";
            $stmt = $pdo->prepare($sql);
            $stmt->bindParam(':codigoBarras', $codigoBarras);
            $stmt->bindParam(':categoria', $categoria);
            $stmt->bindParam(':producto', $producto);
            $stmt->bindParam(':precioCompra', $precioCompra);
            $stmt->bindParam(':precioVenta', $precioVenta);
            $stmt->bindParam(':beneficio', $beneficio);
            $stmt->bindParam(':stock', $stock);
            $stmt->bindParam(':minimoStock', $minimoStock);
            $stmt->bindParam(':ventas', $ventas);
            $stmt->bindParam(':fechaActualizacion', $fechaActualizacion);

            if ($stmt->execute()) {
                $productosRegistrados = $productosRegistrados + 1;
            } else {
                $productosRegistrados = 0;
            }
        }
    }
    ?>
      

4. Función BuscarIdCategoria

Esta función busca el ID de una categoría en la base de datos a partir de su nombre. Utilizada para relacionar productos con categorías existentes.

 
    <?php
    function BuscarIdCategoria($categoria, $pdo) {
        $sql = "SELECT idCategoria FROM categorias_productos WHERE categoria = :categoria";
        $stmt = $pdo->prepare($sql);
        $stmt->bindParam(':categoria', $categoria);
        $stmt->execute();

        $resultado = $stmt->fetch(PDO::FETCH_ASSOC);

        return ($resultado) ? $resultado['idCategoria'] : null;
    }
    ?>
    

5. Respuesta JSON

Finalmente, el código devuelve una respuesta en formato JSON indicando el número total de categorías y productos registrados.

 
    <?php
    $respuesta['totalCategorias'] = $categoriasRegistradas;
    $respuesta['totalProductos'] = $productosRegistrados;
    echo json_encode($respuesta);
    ?>
    







Publicar un comentario

0 Comentarios