Inicio Apuntes FPApuntes DAW Registro de transacciones exportando a Excel utilizando PHP y MySQL

Registro de transacciones exportando a Excel utilizando PHP y MySQL

Publicado por entreunosyceros
Publicado el: Última actualización:

Tabla de contenido

Una vez más aquí. Hoy vengo a dejar un pequeño artículo para un «señor» que me ha pedido una interfaz web para el registro de transacciones exportando a Excel. Sinceramente, no tengo muy claro para qué, pues transportar una hoja de Excel, tampoco es tan complicado. Pero bueno, tras jugar un poco con el código y utilizando la librería XLSX, pues aquí vengo a prestar el el resultado.

Este proyecto web te permite al usuario registrar transacciones (compras y ventas) y exportarlas a un archivo Excel. Utiliza PHP y MySQL para conectarse a una base de datos y almacenar la información que el usuario proporciona.

Un vistazo al código de este registro de transacciones con exportando a Excel

Registro de transacciones con exportación a Excel

Archivo index.php

Esta es la parte en la que se va a ver todo el «mondongo» de la interfaz. Posiblemente termine separando en diferentes archivos las ventanas modal que utiliza para añadir y editar las transacciones, además de separar también el código PHP que escribe la tabla de productos. Pero por el momento, el código que aquí vamos a ver, funciona:

<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Registro en Excel con PHP y MySQL</title>

    <link rel="icon" href="./img/favicon.ico" type="image/x-icon">
    <link rel="stylesheet" type="text/css" href="./css/style.css">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
    <!-- Data Table -->
    <link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/jquery.dataTables.css" />
    <!--  Font Awesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">


</head>

<body>

    <div class="main">
        <div class="header alert alert-dark" role="alert">Transacciones en Excel con PHP y MyQL</div>

        <div class="product-container">

            <div class="product-header mb-2">
                <h3>Lista de transacciones</h3>

                <div class="button-group ml-auto">
                    <button type="button" class="btn btn-success" onclick="exportToExcel()">Exportar a Excel</button>
                    <button type="button" class="btn btn-dark" data-toggle="modal" data-target="#addProductModal">Añadir transacción</button>
                </div>
            </div>

            <!-- Modal para añadir la transacción -->
            <div class="modal fade" id="addProductModal" tabindex="-1" aria-labelledby="addProduct" aria-hidden="true">
                <div class="modal-dialog">
                    <div class="modal-content mt-5">
                        <div class="modal-header">
                            <h5 class="modal-title" id="addProduct">Añadir</h5>
                            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <div class="modal-body">
                            <form action="./actions/add-product.php" method="POST">
                                <div class="form-group">
                                    <label for="Client">Nombre de Cliente*:</label>
                                    <input type="text" class="form-control" id="Client" name="people" required>
                                </div>
                                <div class="form-group">
                                    <label for="Nif_Cif">NIF/CIF*:</label>
                                    <input type="text" class="form-control" id="Nif_Cif" name="nif_cif" required>
                                </div>
                                <div class="form-group">
                                    <label for="Transaction">Transacción:</label>
                                    <select class="form-control" id="Transaction" name="transaction">
                                        <option value="compra">Compra</option>
                                        <option value="venta" selected>Venta</option>
                                    </select>
                                </div>
                                <hr />
                                <div class="form-group">
                                    <label for="productName">Nombre de Producto*:</label>
                                    <input type="text" class="form-control" id="productName" name="product_name" required>
                                </div>
                                <div class="form-group">
                                    <label for="productCode">Código de Producto*:</label>
                                    <input type="text" class="form-control" id="productCode" name="product_code" required>
                                </div>
                                <div class="row">
                                    <div class="col">
                                        <div class="form-group">
                                            <label for="quantity">Cantidad*:</label>
                                            <input type="text" class="form-control" id="quantity" name="quantity" required>
                                        </div>
                                    </div>
                                    <div class="col">
                                        <div class="form-group">
                                            <label for="price">Precio*:</label>
                                            <input type="text" class="form-control" id="price" name="price" required>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label for="notes">Notas:</label>
                                    <textarea class="form-control" id="notes" name="notes" rows="4"></textarea>
                                </div>
                                <div class="aclaration form-group">
                                    <span id="aclaracion">Los campos con * son obligatorios</span>
                                </div>
                                <button type="submit" class="btn btn-primary form-control mt-1 mb-1">Guardar Cambios</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Modal para actualizar la transacción -->
            <div class="modal fade" id="updateProductModal" tabindex="-1" aria-labelledby="updateProduct" aria-hidden="true">
                <div class="modal-dialog">
                    <div class="modal-content mt-5">
                        <div class="modal-header">
                            <h5 class="modal-title" id="updateProduct">Actualizar</h5>
                            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <div class="modal-body">
                            <form action="./actions/update-product.php" method="POST">
                                <div class="form-group" hidden>
                                    <label for="updateProductID">ID de Producto</label>
                                    <input type="text" class="form-control" id="updateProductID" name="tbl_product_id">
                                </div>
                                <div class="form-group">
                                    <label for="updateClient">Nombre de cliente*:</label>
                                    <input type="text" class="form-control" id="updateClient" name="people" required>
                                </div>
                                <div class="form-group">
                                    <label for="updateNif_Cif">NIF/CIF*:</label>
                                    <input type="text" class="form-control" id="updateNif_Cif" name="nif_cif" required>
                                </div>
                                <div class="form-group">
                                    <label for="updateTransaction">Transacción:</label>
                                    <input type="text" class="form-control" id="updateTransaction" name="transaction" readonly>
                                </div>
                                <hr />
                                <div class="form-group">
                                    <label for="updateProductName">Nombre de Producto*:</label>
                                    <input type="text" class="form-control" id="updateProductName" name="product_name" required>
                                </div>
                                <div class="form-group">
                                    <label for="updateProductCode">Código de Producto*:</label>
                                    <input type="text" class="form-control" id="updateProductCode" name="product_code" required>
                                </div>
                                <div class="row">
                                    <div class="col">
                                        <div class="form-group">
                                            <label for="updateQuantity">Cantidad*:</label>
                                            <input type="text" class="form-control" id="updateQuantity" name="quantity" required>
                                        </div>
                                    </div>
                                    <div class="col">
                                        <div class="form-group">
                                            <label for="updatePrice">Precio (€)*:</label>
                                            <input type="text" class="form-control" id="updatePrice" name="price" required>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label for="updateNotes">Notas:</label>
                                    <textarea class="form-control" id="updateNotes" name="notes" rows="4"></textarea>
                                </div>
                                <div class="aclaration form-group">
                                    <span id="aclaracion">Los campos con * son obligatorios</span>
                                </div>
                                <button type="submit" class="btn btn-primary form-control mt-1 mb-1">Guardar Cambios</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>

            <table class="table table-hover product-table">
                <thead>
                    <tr>
                        <th scope="col">ID</th>
                        <th scope="col">Producto</th>
                        <th scope="col">Código</th>
                        <th scope="col">Cantidad</th>
                        <th scope="col">Precio</th>
                        <th scope="col">Total</th>
                        <th scope="col">Fecha</th>
                        <th scope="col">Transacción</th>
                        <th scope="col">Cliente</th>
                        <th scope="col">NIF/CIF</th>
                        <th scope="col" style="display: none;">Nota</th>
                        <th scope="col">Acciones</th>
                    </tr>
                </thead>
                <tbody>

                    <?php
                    include('./connection/con.php');

                    $stmt = $conn->prepare("SELECT * FROM tbl_product");
                    $stmt->execute();

                    $result = $stmt->fetchAll();

                    foreach ($result as $row) {
                        $productID = $row['tbl_product_id'];
                        $productName = $row['product_name'];
                        $productCode = $row['product_code'];
                        $quantity = $row['quantity'];
                        $quantityT = $quantity;
                        $quantity = number_format($quantity, 0, '.', '.');
                        $price = $row['price'];
                        $priceT = $price;
                        // Reemplazamos las , por . en el precio
                        $price = str_replace('.', ',', $price);
                        $date = $row['date'];
                        $timestamp = strtotime($date);
                        // Formatear la fecha según el formato deseado
                        $date = date("H:i, d-m-Y", $timestamp);
                        $transaction = $row['transaction'];
                        $people = $row['people'];
                        $nif_cif = $row['nif_cif'];
                        $notes = $row['notes'];
                        $total = $quantityT * $priceT;
                        // Formatear el total con comas y dos decimales
                        $totalFormatted = number_format($total, 2, ',', '.');
                    ?>

                        <tr>
                            <th scope="row" id="productID-<?= $productID ?>"><?= $productID ?></th>
                            <td id="productName-<?= $productID ?>"><?= $productName ?></td>
                            <td id="productCode-<?= $productID ?>"><?= $productCode ?></td>
                            <td id="quantity-<?= $productID ?>"><?= $quantity ?></td>
                            <td id="price-<?= $productID ?>"><?= str_replace('€', '', $price) ?> €</td>
                            <td id="total-<?= $productID ?>"><?= $totalFormatted ?></td>
                            <td id="date-<?= $productID ?>"><?= $date ?></td>
                            <td id="transaction-<?= $productID ?>"><?= $transaction ?></td>
                            <td id="people-<?= $productID ?>"><?= $people ?></td>
                            <td id="nif_cif-<?= $productID ?>"><?= $nif_cif ?></td>
                            <td id="notes-<?= $productID ?>" style="display: none;"><?= $notes ?></td>
                            <td>
                                <button type="button" class="btn btn-primary" style="font-size: 12px;" onclick="updateProduct(<?= $productID ?>)">
                                    Editar</button>
                                <button type="button" class="btn btn-danger" style="font-size: 12px;" onclick="deleteProduct(<?= $productID ?>)">
                                    Eliminar</button>
                                <?php if (!empty($notes)) : ?>
                                    <button type="button" class="btn btn-info" style="font-size: 12px;" onclick="openNoteModal('<?= $productID ?>', '<?= $notes ?>')">
                                        Ver Nota
                                    </button>
                                <?php endif; ?>

                            </td>
                        </tr>

                    <?php
                    }

                    ?>

                </tbody>
            </table>

        </div>
    </div>

        <!-- Footer -->
    <footer class="footer">
        <div class="container">
            <span class="text-muted">entreunosyceros.net</span>
        </div>
    </footer>

    <!-- Boostrap JS -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js"></script>

    <!-- Librería SheetJS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.0/xlsx.full.min.js"></script>


    <!-- DataTables JS -->
    <script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.js"></script>

    <!-- Funciones Jquery -->
    <script src="./js/script.js"></script>

    <!-- Javascript Notas -->
    <script>
        function openNoteModal(productID, note) {
            var options = {
                title: 'Nota de la transacción con ID: ' + productID,
                width: 400,
                height: 200,
                left: (window.innerWidth - 400) / 2,
                top: (window.innerHeight - 300) / 2,
                resizable: 'yes',
                scrollbars: 'no',
                status: 'no',
                toolbar: 'no',
                menubar: 'no'
            };

            var customAlert = window.open('', '', 'width=' + options.width + ', height=' + options.height + ', left=' + options.left + ', top=' + options.top + ', resizable=' + options.resizable + ', scrollbars=' + options.scrollbars + ', status=' + options.status + ', toolbar=' + options.toolbar + ', menubar=' + options.menubar);

            // html de la nota
            customAlert.document.write('<html><head><title>' + options.title + '</title></head><body style="background-color: #ffffcc;"><p><b>Nota de la transacción con ID ' + productID + ':</b> ' + note + '</p></body></html>');
        }
    </script>
</body>

</html>

Funcionalidad de este registro de transacciones con exportando a Excel

La página web tiene dos secciones principales:

  • Lista de transacciones: Esta sección muestra una tabla con un listado de todas las transacciones registradas. Cada fila de la tabla muestra la siguiente información:
    • ID
    • Producto
    • Código
    • Cantidad
    • Precio
    • Total
    • Fecha
    • Transacción
    • Cliente
    • NIF/CIF
    • Acciones (Editar, Eliminar, Ver Nota)
  • Añadir transacción: Esta sección te permite agregar una nueva transacción a la base de datos. Es necesario completar la siguiente información:
    • Nombre del cliente (obligatorio)
    • NIF/CIF (obligatorio)
    • Tipo de transacción (compra o venta)
    • Nombre del producto (obligatorio)
    • Código del producto (obligatorio)
    • Cantidad (obligatorio)
    • Precio (obligatorio)
    • Notas (opcional)

Explicación del código

El fragmento de código proporcionado muestra la estructura HTML de la página web. Este archivo incluye los siguientes elementos:

  • HTML: La estructura básica de la página web.
  • Head: Contiene información sobre el documento, incluido el título, la codificación de caracteres y enlaces a recursos externos como hojas de estilo.
  • Body: Contiene el contenido visible de la página web, incluido el encabezado, el contenedor del producto, el pie de página y el código JavaScript.
  • Header: Muestra el título de la página web.
  • Contenedor del producto: Esta sección contiene la lista de transacciones y el formulario para agregar una nueva transacción.
    • Encabezado del producto: Muestra el título «Lista de transacciones» y dos botones:
      • Exportar a Excel: Este botón activa una función JavaScript para exportar los datos de la transacción a un archivo Excel.
      • Añadir transacción: Este botón abre una ventana modal donde se puede añadir una nueva transacción.
    • Lista de transacciones: Esta sección utiliza un plugin de DataTables para mostrar una tabla dinámica con la lista de transacciones.
    • Modal de añadir transacción: Esta es una ventana emergente que aparece al hacer clic en el botón «Añadir transacción». Contiene un formulario para ingresar la información de una nueva transacción.
  • Footer: Muestra información.

Archivo con.php

añadir transacciones

Dentro de este archvio, se incluye una llamada al archivo config.php, que es el de las credenciales para conectarse a la base de datos MySQL. Este archivo archivo de conexión es crucial para que el proyecto funcione correctamente.

<?php
require_once 'config.php';

try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo "Fallo en la conexión: " . $e->getMessage();
}
?>

Explicación del código:

  • Variables de conexión:
    • $servername: Almacena el nombre del servidor de la base de datos.
    • $dbname: Almacena el nombre de la base de datos a la que se desea conectar.
    • $username: Almacena el nombre de usuario de la base de datos.
    • $password: Almacena la contraseña del usuario de la base de datos.
  • Establecimiento de la conexión:
    • Se utiliza la clase PDO de PHP para establecer la conexión con la base de datos.
    • Pasaremos la información de la conexión como argumentos al constructor de la clase PDO.
    • Se configura el modo de error de PDO a PDO::ERRMODE_EXCEPTION para que se lance una excepción en caso de error.

Uso del archivo de conexión:

El archivo de conexión se incluye en las páginas PHP que necesitan acceder a la base de datos. En este ejemplo, se incluye el archivo config.php al inicio del script. Luego, se utiliza la variable $conn para ejecutar la consulta SQL en cualquiera de los archivos php.

Archivo add-product

<?php
include("../connection/con.php");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Validar que todos los campos requeridos estén presentes y no estén vacíos
    $requiredFields = ['product_name', 'product_code', 'quantity', 'price', 'transaction', 'people', 'nif_cif'];
    $missingFields = array_filter($requiredFields, function($field) {
        return !isset($_POST[$field]) || empty($_POST[$field]);
    });

    if (!empty($missingFields)) {
        // Mostrar mensaje de error si faltan campos requeridos
        $errorMessage = "Por favor, complete todos los campos.";
        redirectToIndex($errorMessage);
    }

    // Validar datos numéricos
    $numericFields = ['quantity', 'price'];
    $invalidNumericFields = array_filter($numericFields, function($field) {
        return !is_numeric($_POST[$field]);
    });

    if (!empty($invalidNumericFields)) {
        // Mostrar mensaje de error si hay campos numéricos no válidos
        $errorMessage = "La cantidad y el precio deben ser números válidos.";
        redirectToIndex($errorMessage);
    }

    // Procesar los datos insertados
    try {
        $productName = $_POST['product_name'];
        $productCode = $_POST['product_code'];
        $quantity = $_POST['quantity'];
        $price = $_POST['price'];
        // Reemplazamos las , por . en el precio para guardarlo en la base de datos
        $price = str_replace(',', '.', $price);
        $date = date("Y-m-d H:i:s");
        $transaction = $_POST['transaction'];
        $people = $_POST['people'];
        $nif_cif = $_POST['nif_cif'];
        $notes = isset($_POST['notes']) ? $_POST['notes'] : '';

        // Insertar datos en la base de datos
        $stmt = $conn->prepare("INSERT INTO tbl_product (product_name, product_code, quantity, price, date, transaction, people, nif_cif, notes) 
            VALUES (:product_name, :product_code, :quantity, :price, :date, :transaction, :people, :nif_cif, :notes)");

        $stmt->bindParam(":product_name", $productName, PDO::PARAM_STR);
        $stmt->bindParam(":product_code", $productCode, PDO::PARAM_STR);
        $stmt->bindParam(":quantity", $quantity, PDO::PARAM_INT);
        $stmt->bindParam(":price", $price, PDO::PARAM_STR);
        $stmt->bindParam(":date", $date, PDO::PARAM_STR);
        $stmt->bindParam(":transaction", $transaction, PDO::PARAM_STR);
        $stmt->bindParam(":people", $people, PDO::PARAM_STR);
        $stmt->bindParam(":nif_cif", $nif_cif, PDO::PARAM_STR);
        $stmt->bindParam(":notes", $notes, PDO::PARAM_STR);

        $stmt->execute();

        // Redirigir con mensaje de éxito
        $successMessage = "Registro añadido correctamente.";
        redirectToIndex($successMessage);
    } catch (PDOException $e) {
        // Mostrar mensaje de error en caso de excepción
        $errorMessage = "Error al insertar el registro: " . $e->getMessage();
        redirectToIndex($errorMessage);
    } finally {
        // Cerrar la conexión a la base de datos
        $conn = null;
    }
} else {
    // Si no es una solicitud POST, redirigir con mensaje de error
    $errorMessage = "Acceso no permitido.";
    redirectToIndex($errorMessage);
}

function redirectToIndex($message) {
    $timestamp = time();
    echo "<script>
            alert('$message');
            window.location.href = 'http://localhost/inventario-excel/?timestamp=$timestamp';
          </script>";
    exit();
}
?>

Inclusión del archivo de conexión:

  • include("../connection/con.php");: El código incluye el archivo con.php ubicado en la carpeta connection, el cual contiene la información necesaria para establecer la conexión con la base de datos.

Comprobación del método de solicitud:

  • if ($_SERVER['REQUEST_METHOD'] === 'POST') { ... }: Este código verifica si la solicitud que se ha enviado al servidor es de tipo POST, lo cual indica que se pretende insertar un nuevo registro en la base de datos.

Validación de los datos del formulario:

  • Campos requeridos:
    • Se define un arreglo con los nombres de los campos obligatorios (product_name, product_code, quantity, price, transaction, people y nif_cif).
    • Se utiliza la función array_filter para identificar si alguno de estos campos falta o está vacío en la solicitud POST.
    • Si se detectan campos faltantes, se muestra un mensaje de error y se redirige a la página principal.
  • Datos numéricos:
    • Se define un arreglo con los nombres de los campos que deben ser numéricos (quantity y price).
    • Utilizaremos la función array_filter para identificar si alguno de estos campos no contiene un valor numérico válido.
    • Si se detectan valores numéricos inválidos, se muestra un mensaje de error y se redirige a la página principal.

Procesamiento de los datos insertados:

  • Obtención de los datos:
    • Obtendremos los valores de los campos del formulario desde la variable $_POST.
    • Se formatea el precio, reemplazando las comas por puntos, para ajustarlo a la forma en que se almacena en la base de datos.
    • Se obtiene la fecha y hora actual utilizando la función date.
  • Inserción en la base de datos:
    • Se prepara una consulta SQL para insertar los datos en la tabla tbl_product.
    • Utilizaremos marcadores de posición (:product_name, :product_code, etc.) para evitar la inyección SQL.
    • Se enlazan los valores de las variables a los marcadores de posición utilizando la función bindParam.
    • Se ejecuta la consulta SQL.
  • Redirección con mensaje de éxito:
    • Si la inserción se realiza correctamente, se muestra un mensaje de éxito y se redirige a la página principal.

Gestión de errores:

  • Excepciones:
    • Se utiliza un bloque try-catch para atrapar cualquier excepción que pueda ocurrir durante la ejecución de la consulta SQL.
    • Si se produce una excepción, se muestra un mensaje de error y se redirige a la página principal.
  • Acceso no permitido:
    • Si la solicitud no es de tipo POST, se muestra un mensaje de error «Acceso no permitido» y se redirige a la página principal.

Cierre de la conexión a la base de datos:

  • conn = null: Se cierra la conexión a la base de datos al finalizar el script.

Función de redirección:

  • redirectToIndex($message): Esta función muestra un mensaje de alerta JavaScript. Después se redirige al usuario a la página principal del registro de transacciones exportando a Excel utilizando un timestamp para evitar el almacenamiento en caché del navegador.

Archivo delete-product.php

Nota
<?php
// Incluye el archivo de conexión a la base de datos
include("../connection/con.php");

// Verifica si se ha proporcionado un ID de producto a eliminar
if (isset($_GET['product'])) {
    // Obtiene el ID del producto de la URL
    $productID = $_GET['product'];

    try {
        // Prepara la consulta para eliminar el producto con el ID especificado
        $stmt = $conn->prepare("DELETE FROM tbl_product WHERE tbl_product_id = :tbl_product_id");
        
        // Enlaza el parámetro del ID del producto
        $stmt->bindParam(':tbl_product_id', $productID, PDO::PARAM_INT);
        
        // Ejecuta la consulta para eliminar el producto
        $stmt->execute();

        // Redirige de vuelta al index con un mensaje de éxito
        redirectToIndex("Registro eliminado correctamente!!!");
    } catch (PDOException $e) {
        // En caso de error, muestra un mensaje de error
        $errorMessage = "Error al eliminar el registro: " . $e->getMessage();
        redirectToIndex($errorMessage);
    }
} else {
    // Si no se proporciona un ID de producto, redirige de vuelta al index con un mensaje de error
    redirectToIndex("ID de producto no especificado.");
}

// Función para redirigir de vuelta al index con un mensaje
function redirectToIndex($message) {
    echo "<script>
            alert('$message');
            window.location.href = 'http://localhost/inventario-excel/';
          </script>";
    exit();
}

// Cierra la conexión a la base de datos
$conn = null;
?>

Inclusión del archivo de conexión:

  • include("../connection/con.php");: Este código incluye el archivo con.php que contiene la información necesaria para establecer la conexión con la base de datos.

Verificación del ID del producto:

  • if (isset($_GET['product'])) { ... }: Este código verifica si se ha pasado un parámetro product en la URL.

Obtención del ID del producto:

  • $productID = $_GET['product'];: Obtiene el valor del parámetro product y se asigna a la variable $productID.

Eliminación del registro:

  • Preparación de la consulta:
    • Se crea una consulta SQL DELETE para eliminar el registro de la tabla tbl_product con el ID especificado.
    • Utilizaremos un marcador de posición :tbl_product_id para evitar la inyección SQL.
  • Enlace del parámetro:
    • Se utiliza la función bindParam para enlazar el valor de la variable $productID al marcador de posición :tbl_product_id.
  • Ejecución de la consulta:
    • Se ejecuta la consulta SQL para eliminar el registro.

Redirección con mensaje:

  • redirectToIndex("Registro eliminado correctamente!!!");: Se utiliza la función redirectToIndex para redirigir al usuario a la página principal con un mensaje de éxito.

Gestión de errores:

  • Bloque try-catch:
    • Se utiliza un bloque try-catch para atrapar cualquier excepción que pueda ocurrir durante la ejecución de la consulta SQL.
    • Si se produce una excepción, se muestra un mensaje de error y se redirige al usuario a la página principal.

Redirección en caso de error:

  • redirectToIndex("ID de producto no especificado.");: Si no se ha especificado un ID de producto en la URL, se redirige al usuario a la página principal con un mensaje de error.

Cierre de la conexión a la base de datos:

  • $conn = null;: Se cierra la conexión a la base de datos al finalizar el script.

Función de redirección:

  • redirectToIndex($message): Esta función muestra un mensaje de alerta JavaScript y luego redirige al usuario a la página principal.

El código PHP se encarga de eliminar un registro de la tabla tbl_product en base al ID del producto proporcionado en la URL. Si la eliminación se realiza correctamente, se muestra un mensaje de éxito y se redirige al usuario a la página principal del registro de transacciones con exportación a Excel. En caso de error, se muestra un mensaje informativo y se redirige al usuario a la página principal.

Archivo update-product.php

Editar transacción
<?php
// Incluye el archivo de conexión a la base de datos
include("../connection/con.php");

// Verifica si la solicitud es de tipo POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Verifica si se han proporcionado todos los datos necesarios
    if (isset($_POST['product_name'], $_POST['product_code'], $_POST['quantity'], $_POST['price'], $_POST['people'], $_POST['nif_cif'])) {
        // Obtiene los datos del formulario
        $productID = $_POST['tbl_product_id'];
        $productName = $_POST['product_name'];
        $productCode = $_POST['product_code'];
        $quantity = $_POST['quantity'];
        $price = $_POST['price'];
        // Reemplazamos las , por . en el precio para guardarlo en la base de datos
        $price = str_replace(',', '.', $price);
        
        // Elimina el símbolo de moneda del precio
        $price = preg_replace('/[^0-9,.]/', '', $price);
        // Reemplaza las comas por puntos en el precio
        $price = str_replace(',', '.', $price);
        
        // Obtiene la fecha actual
        $date = date("Y-m-d H:i:s");
        
        // Obtiene los datos restantes del formulario
        $transaction = $_POST['transaction'];
        $people = $_POST['people'];
        $nif_cif = $_POST['nif_cif'];
        $notes = $_POST['notes'];

        try {
            // Prepara la consulta para actualizar el registro en la base de datos
            $stmt = $conn->prepare("UPDATE tbl_product 
            SET product_name = :product_name, product_code = :product_code, quantity = :quantity, price = :price, date = :date, transaction = :transaction, people = :people, nif_cif = :nif_cif, notes = :notes 
            WHERE tbl_product_id = :tbl_product_id");

            // Enlaza los parámetros de la consulta
            $stmt->bindParam(":tbl_product_id", $productID, PDO::PARAM_INT);
            $stmt->bindParam(":product_name", $productName, PDO::PARAM_STR);
            $stmt->bindParam(":product_code", $productCode, PDO::PARAM_STR);
            $stmt->bindParam(":quantity", $quantity, PDO::PARAM_STR);
            $stmt->bindParam(":price", $price, PDO::PARAM_STR);
            $stmt->bindParam(":date", $date, PDO::PARAM_STR);
            $stmt->bindParam(":transaction", $transaction, PDO::PARAM_STR);
            $stmt->bindParam(":people", $people, PDO::PARAM_STR);
            $stmt->bindParam(":nif_cif", $nif_cif, PDO::PARAM_STR);
            $stmt->bindParam(":notes", $notes, PDO::PARAM_STR);

            // Ejecuta la consulta
            $stmt->execute();

            // Redirige de vuelta al index con un mensaje de éxito
            redirectToIndex("Registro actualizado correctamente!!!");

        } catch (PDOException $e) {
            // En caso de error, muestra un mensaje de error
            $errorMessage = "Error al actualizar el registro: " . $e->getMessage();
            redirectToIndex($errorMessage);
        }
    } else {
        // Si no se proporcionan todos los datos, muestra un mensaje de error
        redirectToIndex("Debes rellenar todas las casillas!!!");
    }
}

// Función para redirigir de vuelta al index con un mensaje
function redirectToIndex($message) {
    $timestamp = time();
    echo "<script>
            alert('$message');
            window.location.href = 'http://localhost/inventario-excel/?timestamp=$timestamp';
          </script>";
    exit();
}

Inclusión del archivo de conexión:

  • include("../connection/con.php");: Este código incluye el archivo con.php que contiene la información necesaria para establecer la conexión con la base de datos.

Verificación del método de solicitud:

  • if ($_SERVER['REQUEST_METHOD'] === 'POST') { ... }: El código verifica si la solicitud que se ha enviado al servidor es de tipo POST, lo cual indica que se pretende actualizar un registro en la base de datos.

Validación de los datos del formulario:

  • if (isset($_POST['product_name'], $_POST['product_code'], $_POST['quantity'], $_POST['price'], $_POST['people'], $_POST['nif_cif'])) { ... }: Este código verifica si se han proporcionado todos los datos necesarios para actualizar el registro.

Obtención de los datos del formulario:

  • Se obtienen los valores de los campos del formulario desde la variable $_POST.
  • Se formatea el precio, reemplazando las comas por puntos y eliminando el símbolo de moneda, para ajustarlo a la forma en que se almacena en la base de datos.
  • Obtendremos la fecha actual utilizando la función date.

Actualización del registro:

  • Preparación de la consulta:
    • Se crea una consulta SQL UPDATE para actualizar el registro en la tabla tbl_product.
    • Se utilizan marcadores de posición para evitar la inyección SQL.
  • Enlace de los parámetros:
    • Se utiliza la función bindParam para enlazar los valores de las variables a los marcadores de posición de la consulta.
  • Ejecución de la consulta:
    • Ejecutamos la consulta SQL para actualizar el registro.

Redirección con mensaje:

  • redirectToIndex("Registro actualizado correctamente!!!");: Se utiliza la función redirectToIndex para redirigir al usuario a la página principal con un mensaje de éxito.

Gestión de errores:

  • Bloque try-catch:
    • Se utiliza un bloque try-catch para atrapar cualquier excepción que pueda ocurrir durante la ejecución de la consulta SQL.
    • En caso de producirse una excepción, se muestra un mensaje de error y se redirige al usuario a la página principal.

Redirección en caso de datos incompletos:

  • redirectToIndex("Debes rellenar todas las casillas!!!");: Si no se han proporcionado todos los datos necesarios, se redirige al usuario a la página principal con un mensaje de error.

Función de redirección:

  • redirectToIndex($message): Esta función muestra un mensaje de alerta JavaScript y luego redirige al usuario a la página principal.

Este código PHP se encarga de actualizar un registro en la tabla tbl_product con los datos proporcionados en el formulario. Si la actualización se realiza correctamente, se muestra un mensaje de éxito y se redirige al usuario a la página principal del registro de transacciones con exportación a Excel. En caso de error o si no se han proporcionado todos los datos necesarios, se muestra un mensaje informativo y se redirige al usuario a la página principal.

Archivo script.js

exportación a una hoja de excel
$(document).ready(function() {
    $('.product-table').DataTable();
});

function updateProduct(id) {
    $("#updateProductModal").modal("show");

    let updateProductID = $("#productID-" + id).text();
    let updateClient = $("#people-" + id).text();
    let updateNif_Cif = $("#nif_cif-" + id).text();
    let updateTransaction = $("#transaction-" + id).text();
    let updateProductName = $("#productName-" + id).text();
    let updateProductCode = $("#productCode-" + id).text();
    let updateQuantity = $("#quantity-" + id).text();
    let updatePrice = $("#price-" + id).text();
    let updateNotes = $("#notes-" + id).text();
    console.log($("#notes-" + id).text())
    // Eliminar el símbolo € del precio
    updatePrice = updatePrice.replace('€', '');

    $("#updateProductID").val(updateProductID);
    $("#updateClient").val(updateClient);
    $("#updateNif_Cif").val(updateNif_Cif);
    $("#updateTransaction").val(updateTransaction);
    $("#updateProductName").val(updateProductName);
    $("#updateProductCode").val(updateProductCode);
    $("#updateQuantity").val(updateQuantity);
    $("#updatePrice").val(updatePrice);
    $("#updateNotes").val(updateNotes);
}


function deleteProduct(id) {
    if (confirm('Deseas eliminar este producto?')) {
        window.location.href = "./actions/delete-product.php?product=" + id;
    }
}


function exportToExcel() {
    // Get table data
    var table = $('.product-table').DataTable();
    var data = table.rows().data().toArray();

    // Remove the "Action" column from the data
    var filteredData = data.map(function(row) {
        return row.slice(0, row.length - 1);
    });

    // Create a worksheet
    var ws = XLSX.utils.aoa_to_sheet([
        ['ID', 'Producto', 'Código', 'Cantidad', 'Precio', 'Total','Fecha', 'Trasacción', 'Cliente', 'NIF/CIF', 'Notas']
    ].concat(filteredData));

    // Create a workbook
    var wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'entreunosyceros.net');

    // Save the workbook as an Excel file
    XLSX.writeFile(wb, 'inventario-excel.xlsx');
}

Este fragmento de código se compone de tres partes principales:

Inicialización de DataTable:

  • Este código utiliza la librería JavaScript jQuery.
  • Espera a que el documento esté completamente cargado ($(document).ready(function() { ... })).
  • Luego, selecciona el elemento con la clase product-table y le aplica el plugin DataTable.
  • El plugin DataTable se utiliza para mejorar la funcionalidad de la tabla de lista de productos, agregando características como clasificación, filtrado y paginación.

Funcionalidad de actualización de productos:

  • Esta función, updateProduct, toma un parámetro id que representa el identificador único del producto.
  • Muestra el elemento modal con el ID updateProductModal usando la función modal de jQuery, abriendo una ventana modal para actualizar la información del producto.
  • Luego, recupera valores de varios elementos HTML con IDs específicos que corresponden a los detalles del producto mostrados en la tabla.
  • Los valores recuperados se establecen luego como valores de los campos de formulario correspondientes en el modal de actualización usando selectores jQuery.

Funcionalidad de eliminación y exportación de este registro de transacciones exportando a Excel

  • La función deleteProduct toma un parámetro id y utiliza un cuadro de diálogo de confirmación antes de redirigir al usuario al script delete-product.php, es responsable de eliminar el producto de la base de datos.
  • La función exportToExcel recupera datos de la tabla product-table utilizando el plugin DataTable.
  • Luego filtra los datos para eliminar la columna «Acción» antes de crear un libro de Excel utilizando la librería XLSX.
  • Finalmente, guarda la hoja como un archivo llamado inventario-excel.xlsx.

Este fragmento de código demuestra funcionalidades relacionadas con la gestión de una lista de productos mostrada en una tabla. Utiliza librerías JavaScript como jQuery y, potencialmente, DataTable y XLSX para lograr funcionalidades como mejoras en la tabla, interacción con modales, actualizaciones, eliminaciones de productos y exportación de datos en este registro de transacciones exportando a Excel.

Archivo style.css

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500&display=swap');

* {
    margin: 0;
    padding: 0;
    font-family: 'Poppins', sans-serif !important;
}

.main {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.header {
    text-align: center;
    font-size: 40px;
    font-weight: bold;
    padding: 20px;
    width: 100%;
}

.alert-dark {
    color: #e9e9e9 !important;
    background-color: #60007a !important;
}

.product-container {
    position: relative; /* Importante para que los elementos absolutos se posicionen en relación con este contenedor */
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 80%;
    height: auto; /* Permitir que el contenedor crezca según el contenido */
    min-height: 680px; /* Establecer una altura mínima si es necesario */
    margin: 35px;
    margin-top: 35px;
    border-radius: 20px;
    box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    background: #fff;
}

.product-header {
    display: flex;
    align-items: center;
    width: 95%;
    height: 50px;
    margin-top: 30px;
}

.product-header h3 {
    font-weight: bold;
}

.dataTables_wrapper {
    position: relative; /* Importante para que los elementos absolutos se posicionen en relación con este contenedor */
    width: 95% !important;
    box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
    padding: 20px;
    border-radius: 10px;
    height: 83%;
    text-align: center !important;
    margin-bottom: 50px; /* Añade margen inferior para dejar espacio para la paginación */
}


.dataTables_info {
    position: absolute; /* Cambiado a absolute */
    bottom: -45px; /* Mueve la paginación hacia abajo */
    left: 10px; /* Ajusta la posición izquierda */
    clear: both !important;
    float: left !important;
    padding-top: 0.755em;
}

.dataTables_paginate {
    position: absolute; /* Cambiado a absolute */
    bottom: -45px; /* Mueve la paginación hacia abajo */
    right: 0px; /* Ajusta la posición derecha */
}

table.dataTable thead>tr>th.sorting,
table.dataTable thead>tr>th.sorting_asc,
table.dataTable thead>tr>th.sorting_desc,
table.dataTable thead>tr>th.sorting_asc_disabled,
table.dataTable thead>tr>th.sorting_desc_disabled,
table.dataTable thead>tr>td.sorting,
table.dataTable thead>tr>td.sorting_asc,
table.dataTable thead>tr>td.sorting_desc,
table.dataTable thead>tr>td.sorting_asc_disabled,
table.dataTable thead>tr>td.sorting_desc_disabled {
    text-align: center;
}

td {
    text-align: center;
}

.modal-content {
    margin-top: 100px !important;
}

label, .modal-title{
    font-weight: bold !important;
}

.aclaration{
    font-size: small;
    text-align: center;
}

/* Estilos generales */
.product-container {
    margin-top: 20px;
}

.product-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.button-group {
    display: flex;
    align-items: center;
}

.footer {
    position: fixed;
    bottom: 0;
    width: 100%;
    background-color: #f8f8f8;
    padding: 10px 0;
    text-align: center;
    z-index: -1;
    box-shadow: rgba(0, 0, 0, 0.35) 15px 5px 15px;
}

Importación de fuente:

  • Esta línea importa la fuente Poppins de Google Fonts, especificando un grosor de 500 (mediana).
  • El parámetro display=swap asegura que la fuente se intercambie rápidamente, lo que puede mejorar la velocidad de renderizado inicial.

Estilos globales:

  • Este bloque aplica estilos a todos los elementos (*) del documento.
  • Establece margin y padding a 0 para eliminar los márgenes y rellenos predeterminados del navegador.
  • La font-family la pondremos como Poppins, con sans-serif como alternativa si Poppins no está disponible. La regla !important asegura que este estilo anule cualquier estilo conflictivo.

El .main:

  • Esta define estilos para elementos con la clase main.
  • Pondremos la visualización como flex, organizando los elementos hijos horizontalmente en una columna.
  • Establece la flex-direction como column, apilando los elementos verticalmente uno tras otro.
  • Establece align-items como center, centrando horizontalmente los elementos dentro del contenedor.

Clase .header:

  • Esta define estilos para elementos con la clase header.
  • Establece la alineación del texto como center.
  • Se establece el tamaño de la fuente a 40 píxeles para encabezados más grandes.
  • Establece el grosor de la fuente como bold para una mayor presencia.
  • Agrega 20 píxeles de relleno en todos los lados para el espaciado.
  • Establece el ancho al 100%.

Clase .alert-dark:

  • Esta define estilos para elementos con la clase alert-dark. Estos podrían ser cuadros de alerta o elementos destinados a tener una apariencia oscura e informativa.
  • Pondremos el color del texto a un gris claro (#e9e9e9) usando !important para anular los valores predeterminados.
  • Establece el color de fondo a un azul oscuro (#60007a) usando !important para una posible anulación.

.product-container:

  • Esta define estilos para elementos con la clase product-container, que probablemente representa un contenedor para información de productos.
  • Establece la position como relative para permitir el posicionamiento absoluto de los elementos hijos dentro.
  • Usa propiedades flexbox similares (display, flex-direction, align-items) como la clase .main para el diseño.
  • Se establece el ancho al 80% del visor.
  • Establece la altura como auto para adaptarse al contenido, con una min-height mínima de 680px para la consistencia.
  • Agrega márgenes de 35px en todos los lados y un margen superior adicional de 35px para un posible espaciado.

La clase .product-header:

  • Define estilos para elementos con la clase product-header.
  • Establece la display como flex para organizar los elementos hijos horizontalmente.
  • Centra los elementos verticalmente con align-items: center.
  • Establece el ancho al 95% del contenedor padre.
  • Establece la altura a 50px para una altura fija del encabezado.
  • Agrega un margen superior de 30px para separar el encabezado del contenido.
  • Anida un selector h3 dentro de .product-header para aplicar un estilo de font-weight: bold al título del encabezado.

Estilos específicos de la tabla:

  • Se definen estilos específicos para la tabla utilizando clases y selectores específicos de DataTables.
  • Se establece la position como relative para el contenedor dataTables_wrapper para permitir el posicionamiento absoluto de elementos dentro.
  • Ajustaremos el ancho al 95% y se aplica un !important para anular posibles estilos conflictivos.
  • Añadimos una sombra de caja sutil.
  • Se establece un margen inferior de 50px para dejar espacio para la paginación.
  • Se reposicionan los elementos de información y paginación (dataTables_info y dataTables_paginate) usando position: absolute y ajustando bottom, left y right.
  • Se centra el texto de las cabeceras y celdas de la tabla usando text-align: center.

Con esto, aun que no está todo el código, creo que le hemos dado un vistazo por encima a las partes más importantes de esta interfaz web para el registro de transacciones exportando a Excel. El código fuente al completo se pueden ver en el repositorio de GitHub en el que he subido el proyecto.

Si quieres ver este registro de transacciones exportando a Excel funcionando, puedes dirigirte a la sección de ejemplos que hay disponible en esta página web.

También te puede interesar ...

Deja un comentario

* Al utilizar este formulario, aceptas que este sitio web almacene y maneje tus datos.

Adblock Detectado!!

Ayúdanos deshabilitando la extensión AdBlocker de tu navegador para visitar esta web.
Si no sabes hacerlo en Chrome, consulta el siguiente enlace. Si utilizas Firefox, puedes consultar este otro enlace.
Esto mejorará tu experiencia en este sitio web.