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.
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.
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.
Ahora lo que resta es tomar este HTML y generar el PDF a partir del mismo: justo lo que hace dompdf.
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:
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:
Como ves la impresión es perfecta además de que la fuente (DejaVu Sans) le da una buena presentació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.
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.
Ver comentarios
Que tipo de impresora termica usas para estos ejemplos?
El ticket que aparece en el post fue impreso en una Xprinter 58
Tengo problemas con el salto de pagina, en la impresora termica da problemas porque imprime por partes
Hola. Gracias por sus comentarios. Si tiene alguna consulta, solicitud de creación de un programa o solicitud de cambio de software estoy para servirle en https://parzibyte.me/#contacto
Saludos!
Si el cliente quiere factura en formato ticket como sería?
Hola. No lo sé, depende del formato, pero todo se podría acomodar de manera vertical para hacer que quepa en el espacio reducido del ticket.
Saludos :)