Ir al contenido principal
Versión: 1.x

Plantillas para impresoras térmicas

Las plantillas térmicas utilizan un formato XML que genera tanto una vista previa en pantalla como comandos de impresora ESC/POS a partir de la misma plantilla. Utilizan los mismos marcadores de posición {{variable}} que las plantillas HTML para enlazar datos.

Elija este motor si tiene una impresora de recibos conectada mediante la configuración de impresoras.

Elementos XML

Elemento raíz

Cada plantilla térmica comienza con un <receipt> raíz:

<receipt paper-width="48">
<!-- 48 characters = 80mm paper -->
<!-- 32 characters = 58mm paper -->
</receipt>

Texto y formato

<text>Plain text</text>
<bold>Bold text</bold>
<underline>Underlined text</underline>
<invert>Inverted (white on black)</invert>

Alineación

<align mode="left">Left aligned</align>
<align mode="center">Centered</align>
<align mode="right">Right aligned</align>

Tamaño del texto

Escalar el ancho y el alto del texto de forma independiente:

<size width="2" height="2">Double-size text</size>
<size width="2" height="1">Wide text</size>
<size width="1" height="2">Tall text</size>

Diseño tabular

Utilice <row> y <col> para columnas alineadas:

<row>
<col width="24">Item name</col>
<col width="8" align="right">Qty</col>
<col width="16" align="right">Price</col>
</row>

Los anchos de columna se expresan en caracteres. Utilice width="*" para una columna flexible que absorba el espacio restante — esto permite que las plantillas funcionen con distintos anchos de papel sin modificaciones:

<row>
<col width="*">{{name}}</col>
<col width="12" align="right">{{line_total_display}}</col>
</row>

Separadores y espaciado

<line /> <!-- Default single rule -->
<line style="double" /> <!-- Printer-native double rule -->
<line style="dashed" /> <!-- Character dashes across the width -->
<line style="dotted" /> <!-- Character dots across the width -->
<feed lines="2" /> <!-- Blank lines -->

<line/> (o style="single") y style="double" imprimen la línea nativa de la impresora. dashed y dotted imprimen separadores basados en caracteres a lo ancho de la columna activa — útil cuando se necesita un separador visible que se conserve en una captura de pantalla de vista previa térmica.

Comandos de impresora

<cut /> <!-- Full paper cut -->
<cut mode="partial" /> <!-- Partial cut (leaves a tab) -->
<drawer /> <!-- Open cash drawer -->

Códigos de barras y códigos QR

<barcode type="code128" height="40">{{order.number}}</barcode>
<barcode type="qrcode" scale="3">{{fiscal.qr_payload}}</barcode>

Ejemplo: recibo simple de 80mm

<receipt paper-width="48">
<align mode="center">
<size width="2" height="2">{{store.name}}</size>
</align>
<feed lines="1" />
<align mode="center">
<text>{{store.address_1}}</text>
<text>{{store.city}} {{store.state}} {{store.postcode}}</text>
{{#store.phone}}<text>{{store.phone}}</text>{{/store.phone}}
</align>
<line />

<text>Order: #{{order.number}}</text>
<text>Date: {{order.created.datetime}}</text>
{{#cashier.name}}<text>Cashier: {{cashier.name}}</text>{{/cashier.name}}
<line />

<!-- Column headers -->
<row>
<col width="*"><bold>Item</bold></col>
<col width="4" align="right"><bold>Qty</bold></col>
<col width="12" align="right"><bold>Total</bold></col>
</row>
<line />

<!-- Line items -->
{{#lines}}
<row>
<col width="*">{{name}}</col>
<col width="4" align="right">{{qty}}</col>
<col width="12" align="right">{{line_total_display}}</col>
</row>
{{/lines}}

<line />

<!-- Totals -->
<row>
<col width="*">Subtotal</col>
<col width="16" align="right">{{totals.subtotal_display}}</col>
</row>
{{#totals.tax_total}}
<row>
<col width="*">Tax</col>
<col width="16" align="right">{{totals.tax_total_display}}</col>
</row>
{{/totals.tax_total}}
<row>
<col width="*"><bold>TOTAL</bold></col>
<col width="16" align="right"><bold>{{totals.total_display}}</bold></col>
</row>

<line />

{{#payments}}
<row>
<col width="*">{{method_title}}</col>
<col width="16" align="right">{{amount_display}}</col>
</row>
{{#tendered}}
<row>
<col width="*">Tendered</col>
<col width="16" align="right">{{tendered_display}}</col>
</row>
<row>
<col width="*">Change</col>
<col width="16" align="right">{{change_display}}</col>
</row>
{{/tendered}}
{{/payments}}

<feed lines="2" />
<align mode="center">
<text>Thank you for your purchase!</text>
</align>
<feed lines="3" />
<cut />
</receipt>

Columnas con ancho asterisco

La función width="*" permite que las plantillas sean independientes del ancho del papel. En lugar de definir anchos de columna fijos para un tamaño de papel específico, se utiliza * para la columna que debe expandirse:

<!-- Works on 58mm (32 char) AND 80mm (48 char) printers -->
<row>
<col width="*">{{name}}</col>
<col width="10" align="right">{{line_total_display}}</col>
</row>

En una impresora de 80mm (48 caracteres), el nombre del artículo ocupa 38 caracteres. En una impresora de 58mm (32 caracteres), ocupa 22 caracteres. Las columnas fijas mantienen el mismo tamaño en ambas.

Vista previa de la plantilla

El editor de plantillas muestra una vista previa térmica en tiempo real durante la edición. La vista previa renderiza el XML como HTML monoespaciado con estilos, simulando cómo se verá el recibo impreso. Los cambios se actualizan tras una breve demora (con un debounce de 300ms).

La misma plantilla genera tanto la vista previa como la salida ESC/POS para la impresora — no existe una plantilla de "impresión" separada. Los códigos de barras y códigos QR se renderizan como SVGs en línea en la vista previa y como comandos ESC/POS nativos (o imágenes rasterizadas) en la impresora.

Consejos y errores comunes de creación

La impresión térmica presenta algunas dificultades que no existen en HTML. Estas son las más frecuentes entre los autores de plantillas.

Envolver encabezados con estilo en <text> para un salto de línea

Contenedores con estilo — <bold>, <size>, <underline>, <align>no producen un salto de línea por sí mismos. Solo <text> y los elementos de bloque (<line/>, <row>, <feed>) lo hacen.

<!-- ❌ Bug: the heading runs together with whatever follows -->
<bold>{{i18n.bill_to}}</bold>
{{customer.name}}

<!-- ✅ Fix: wrap the inner content in <text> -->
<bold><text>{{i18n.bill_to}}</text></bold>
<text>{{customer.name}}</text>

Las plantillas de galería incluidas para 80 mm utilizan este patrón en cada encabezado.

Evitar <size width="2"> dentro de filas estrechas

El texto de doble ancho duplica el recuento efectivo de caracteres. Un encabezado que cabe en una impresora de 80 mm puede desbordarse en una impresora genérica de 80 mm con 42 columnas, y en papel de 58 mm solo quedan 16 caracteres.

Para valores destacados (totales grandes, números de orden de cocina), se recomienda emitir una línea escalada independiente en lugar de incluirla dentro de una distribución multicolumna <row>:

<!-- For store names, prefer normal-width, double-height -->
<bold><size height="2"><text>{{store.name}}</text></size></bold>

<!-- For a bold total, put it on its own line above the row -->
<align mode="right">
<bold><size height="2"><text>{{totals.total_display}}</text></size></bold>
</align>

Uso de width="*" para diseños independientes del ancho del papel

La columna width="*" (asterisco) absorbe el ancho restante después de las columnas de ancho fijo. La misma plantilla se renderiza correctamente en impresoras de 32 columnas (58 mm), 42 columnas (80 mm estándar) y 48 columnas (80 mm ancho) sin necesidad de modificación:

<!-- Works on 58mm AND 80mm without changes -->
<row>
<col width="*">{{name}}</col>
<col width="10" align="right">{{line_total_display}}</col>
</row>

Si se utilizan anchos numéricos fijos, el presupuesto de columnas debe ser 42, no 48. Las filas que sumen 48 se ajustarán con salto de línea en las impresoras comunes de 80 mm con 42 columnas.

Encabezados con estilo centrados dentro de bloques <align>

Dentro de <align mode="center"> (o right), un encabezado con estilo directo — <bold>, <size>, <underline>, <invert> colocado directamente dentro <align> — seguido de otra línea se cierra automáticamente en su propia línea. Un nombre de tienda centrado y escalado sobre una línea de dirección centrada se imprime correctamente incluso sin el <text> ajuste explícito.

Fuera de un bloque de alineación, conservar el <text> ajuste explícito.

Normalización de puntuación ESC/POS

Cuando el lenguaje de la impresora es ESC/POS, el codificador normaliza la puntuación tipográfica a ASCII seguro antes de escribir:

  • Raya corta, raya larga, raya de cifras, signo menos Unicode → -
  • Comillas tipográficas → comillas rectas
  • Espacio de no separación → espacio regular

Así, Mon–Sat 9:00–18:00 y "open" se imprimen correctamente incluso en impresoras sin fuente Unicode. Las impresoras Star (star-line / star-prnt) conservan la tipografía original, por lo que se debe utilizar caracteres compatibles con la fuente de la impresora.

Escrituras no latinas y de derecha a izquierda

Las impresoras térmicas imprimen texto utilizando una fuente y página de códigos integradas, por lo que los sistemas de escritura árabe, hebreo, persa, urdu y otros no latinos solo se imprimen correctamente si la impresora está configurada con una página de códigos compatible (p. ej., CP864 / Windows-1256 para árabe); de lo contrario, se obtienen caracteres en blanco o ilegibles.

El método fiable para estos sistemas de escritura es Recibo completo rasterizado, que renderiza todo el recibo como imagen para que se imprima exactamente como fue diseñado, independientemente de las fuentes integradas de la impresora. Consulte Configuración de impresora para activar el modo ráster.

El hardware térmico requiere una plantilla térmica

Una impresora térmica no puede imprimir una plantilla HTML de página completa: el trabajo debe convertirse a comandos ESC/POS o Star, que HTML no puede expresar. Utilice una plantilla térmica para hardware térmico; para HTML de página completa A4/Letter, imprima con una impresora de sistema/PDF o a través de PrintNode.

Logotipos e imágenes

Utilice <image> para insertar un logotipo:

<align mode="center">
<image src="data:image/png;base64,..." />
</align>

WCPOS rasteriza las imágenes en el cliente —decodificación, aplanamiento de transparencias a blanco, redimensionamiento según el presupuesto de puntos de la impresora, conversión a monocromo (difuminado Atkinson para logotipos, umbral para códigos de barras)— y envía comandos de imagen ESC/POS o Star.

  • Presupuesto de puntos: 384 puntos de ancho para 58 mm, 576 puntos de ancho para 80 mm.
  • Fuentes aceptadas: URLs de datos data:image/png y data:image/jpeg, URLs absolutas http(s) y rutas relativas a la raíz del mismo origen. Las rutas relativas al protocolo //, las barras invertidas y el recorrido .. codificado en porcentaje son rechazados.
  • Formato recomendado: PNG de alto contraste con fondo transparente o blanco. JPEG funciona, pero los artefactos de compresión pueden imprimirse como ruido.
  • SVG aún no es compatible con la salida térmica sin formato.

Consejos

  • Comenzar a partir de una plantilla de la galería — las plantillas térmicas de la galería utilizan todos los patrones anteriores y están validadas con impresoras reales.
  • Probar ambos tamaños de papel si las tiendas utilizan diferentes impresoras, o utilizar columnas con width="*".
  • Utilizar los campos _display para moneda — ya están adaptados a la configuración regional.
  • Mantenerlo simple — el formato térmico tiene menos herramientas de formato que HTML por diseño. Aprovechar <row> + <col width="*"> y dejar que la impresora haga su trabajo.