php

Generar ticket PDF con PHP

En este post te mostraré cómo generar un ticket, tiquete o recibo de pago en formato PDF con PHP. No será una factura, sino un ticket que puede ser impreso en una impresora térmica; de este modo puedes generar tickets e imprimirlos del lado del cliente eligiendo cualquier impresora.

Para lograr esta impresión de ticket en una impresora de 58 milímetros o de 80 milímetros vamos a generar un PDF usando dompdf y después mostrando el documento para imprimirlo en el navegador.

Sobre dompdf

Ya he hecho un post dedicado a dompdf; por favor dale una leída para más detalles. Básicamente es cuestión de contar con composer e instalarlo con:

composer require dompdf/dompdf

Después de instalar dompdf recuerda incluir el autoload:

include_once "./vendor/autoload.php";

Te repito, si quieres más detalles puedes ver mi post para generar un PDF con PHP a través de HTML.

Generación del ticket como HTML

Vamos a ver cómo generar el contenido del PDF, para ello me basaré en mi impresión de ticket con JavaScript y lo combinaré con PHP. El código queda así:

<?php
$medidaTicket = 180;

?>
<!DOCTYPE html>
<html>

<head>

    <style>
        * {
            font-size: 12px;
            font-family: 'DejaVu Sans', serif;
        }

        h1 {
            font-size: 18px;
        }

        .ticket {
            margin: 2px;
        }

        td,
        th,
        tr,
        table {
            border-top: 1px solid black;
            border-collapse: collapse;
            margin: 0 auto;
        }

        td.precio {
            text-align: right;
            font-size: 11px;
        }

        td.cantidad {
            font-size: 11px;
        }

        td.producto {
            text-align: center;
        }

        th {
            text-align: center;
        }


        .centrado {
            text-align: center;
            align-content: center;
        }

        .ticket {
            width: <?php echo $medidaTicket ?>px;
            max-width: <?php echo $medidaTicket ?>px;
        }

        img {
            max-width: inherit;
            width: inherit;
        }

        * {
            margin: 0;
            padding: 0;
        }

        .ticket {
            margin: 0;
            padding: 0;
        }

        body {
            text-align: center;
        }
    </style>
</head>

<body>
    <div class="ticket centrado">
        <h1>NOMBRE DEL NEGOCIO</h1>
        <h2>Ticket de venta #12</h2>
        <h2>2020-02-05 00:12:22</h2>
        <?php
        # Recuerda que este arreglo puede venir de cualquier lugar; aquí lo defino manualmente para simplificar
        # Puedes obtenerlo de una base de datos, por ejemplo: https://parzibyte.me/blog/2019/07/17/php-bases-de-datos-ejemplos-tutoriales-conexion/

        $productos = [
            [
                "cantidad" => 31,
                "descripcion" => "Cheetos verdes 80 g",
                "precio" => 123,
            ],
            [
                "cantidad" => 12,
                "descripcion" => "Teclado HyperX",
                "precio" => 1233,
            ],
            [
                "cantidad" => 12,
                "descripcion" => "Mouse Logitech ASD123",
                "precio" => 841,
            ],
            [
                "cantidad" => 15,
                "descripcion" => "Monitor Samsung 123",
                "precio" => 3546,
            ],
        ];
        ?>

        <table>
            <thead>
                <tr class="centrado">
                    <th class="cantidad">CANT</th>
                    <th class="producto">PRODUCTO</th>
                    <th class="precio">$$</th>
                </tr>
            </thead>
            <tbody>
                <?php
                $total = 0;
                foreach ($productos as $producto) {
                    $total += $producto["cantidad"] * $producto["precio"];
                ?>
                    <tr>
                        <td class="cantidad"><?php echo number_format($producto["cantidad"], 2) ?></td>
                        <td class="producto"><?php echo $producto["descripcion"] ?></td>
                        <td class="precio">$<?php echo number_format($producto["precio"], 2) ?></td>
                    </tr>
                <?php } ?>
            </tbody>
            <tr>
                <td class="cantidad"></td>
                <td class="producto">
                    <strong>TOTAL</strong>
                </td>
                <td class="precio">
                    $<?php echo number_format($total, 2) ?>
                </td>
            </tr>
        </table>
        <p class="centrado">¡GRACIAS POR SU COMPRA!
            <br>parzibyte.me</p>
    </div>
</body>

</html>

Como se puede observar, es una simple tabla HTML generada con PHP a partir de un arreglo. Este arreglo puede provenir de cualquier parte, en este caso lo coloqué manualmente para efectos de simplicidad.

El simple HTML generado es el siguiente, y la medida de la tabla no supera el ancho establecido por la variable de la medida, por lo que será perfecta para imprimirla en una impresora térmica.

HTML generado para ticket en PHP

Ahora lo que resta es tomar este HTML y generar el PDF a partir del mismo: justo lo que hace dompdf.

Generando ticket PDF con PHP

Lo que resta es aplicar el truco que vimos en mi post de dompdf; hacemos que se genere el ticket HTML y después obtenemos la salida para enviarla a dompdf, generamos el documento y lo mostramos para que el usuario pueda imprimirlo o descargarlo:

Una cosa importante es que de todos los tamaños de papel que se ofrecen, encontré que el b7 es perfecto para las impresoras de 58 milímetros.

<?php
include_once "./vendor/autoload.php";
use Dompdf\Dompdf;
$dompdf = new Dompdf();
$dompdf->setPaper('b7', 'portrait');
ob_start();
include "./generar_ticket.php";
$html = ob_get_clean();
$dompdf->loadHtml($html);
$dompdf->render();
header("Content-type: application/pdf");
header("Content-Disposition: inline; filename=documento.pdf");
echo $dompdf->output();

Eso habrá generado un PDF:

Ticket PDF generado con PHP – Listo para imprimir

Aunque parece que el PDF está más grande y que el espacio sobrará, al enviarla a una impresora térmica, el tamaño es adecuado:

Ticket PDF impreso en impresora térmica

Como ves la impresión es perfecta además de que la fuente (DejaVu Sans) le da una buena presentación.

Conclusión

Creo que es la cuarta vez que lo cito, pero te lo digo de nuevo, si tienes dudas o quieres explorar más sobre dompdf visita mi otro post.

También he mostrado varias formas de imprimir tickets, por ejemplo:

Igualmente si te gusta PHP te invito a aprender más sobre el lenguaje en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

3 días hace

Esta web usa cookies.