Linguagem dos modelos
Esta página é para quem quer ir além dos modelos prontos e escrever o próprio layout da comanda ou de um complemento. Não é preciso saber programar, mas é preciso atenção: um detalhe fora do lugar pode impedir a impressão. Trabalhe sempre numa cópia do modelo, acompanhe a pré-visualização e faça um Imprimir teste antes de colocar em uso (veja Modelos de comanda).
Como um modelo funciona
Seção intitulada “Como um modelo funciona”Um modelo tem duas camadas, misturadas no mesmo texto:
- Os dados, sempre entre chaves duplas:
{{ empresa.nome }},{{ pesagem.total | moeda }}. Essa camada escreve os dados da comanda, decide o que aparece (condições) e repete linhas (repetições). - O layout, com marcações parecidas com as de uma página de internet:
<p>para parágrafos,<table>para tabelas,<hr/>para linhas separadoras e assim por diante. Essa camada diz como cada coisa é arrumada no papel.
Primeiro o sistema troca tudo o que está entre chaves pelos dados da comanda; depois monta o resultado na largura do papel, em texto de largura fixa, como a impressora térmica imprime. Por exemplo, este modelo:
<p bold text-center>{{ empresa.nome }}</p><p>Comanda N.{{ pesagem.numero }}</p>vira, numa comanda de número 5 do “Restaurante Sabor”:
Restaurante SaborComanda N.5com o nome em negrito e centralizado na linha.
Parte 1: os dados
Seção intitulada “Parte 1: os dados”Variáveis
Seção intitulada “Variáveis”Uma variável é escrita entre {{ e }} e é trocada pelo valor correspondente da comanda. Os nomes são sempre em
letras minúsculas, sem acento, com as palavras separadas por _ e os grupos separados por ponto:
empresa.endereco_completo, pesagem.peso_aferido, configuracao_comanda.mensagem_rodape.
<p>{{ empresa.nome }}</p><p>{{ empresa.cidade }} / {{ empresa.estado }}</p><p>Peso: {{ pesagem.peso_aferido | numero 3 }} kg</p>Se você errar o nome de uma variável, não aparece erro: o lugar dela fica em branco. Quando um dado sumir da pré-visualização, confira a grafia.
Variáveis disponíveis nos modelos de comanda e nos complementos:
| Variável | O que contém |
|---|---|
empresa.nome |
Nome (fantasia) da empresa. |
empresa.endereco |
Logradouro, sem número. |
empresa.endereco_numero |
Número do endereço (opcional). |
empresa.bairro |
Bairro. |
empresa.cidade |
Cidade. |
empresa.estado |
Sigla do estado (UF). |
empresa.cep |
CEP. |
empresa.telefone |
Telefone fixo. |
empresa.celular |
Telefone celular. |
empresa.email |
E-mail de contato. |
empresa.site |
Endereço do site. |
empresa.contato_empresa |
“Telefone / Celular” (só os preenchidos). |
empresa.possui_algum_contato |
Verdadeiro quando telefone ou celular estão preenchidos. |
empresa.endereco_completo |
“Endereço, Número - Bairro” (o número só aparece quando preenchido). |
frase.descricao |
Texto da frase. |
frase.autor |
Autor da frase (opcional). |
configuracao_comanda.exibir_frases |
Imprime a frase do dia quando houver. |
configuracao_comanda.quantidade_linhas_em_branco |
Linhas em branco para anotações: 0 a 20. |
configuracao_comanda.mensagem_rodape |
Mensagem impressa no rodapé (vazia = sem rodapé). |
configuracao_comanda.produtos_adicionais_comanda |
Lista. Produtos adicionais listados na comanda para marcação manual. |
configuracao_comanda.produtos_adicionais_comanda[].ordem |
Posição na lista (ordem crescente). |
configuracao_comanda.produtos_adicionais_comanda[].descricao |
Nome do produto. |
configuracao_comanda.produtos_adicionais_comanda[].valor_unitario |
Preço unitário (nulo = não impresso). |
configuracao_comanda.imprimir_codigo_barras |
Imprime o código de barras na comanda. |
configuracao_comanda.template_codigo |
Modelo de 12 caracteres do código de barras: letras I, C, T, P, Q e dígitos. |
pesagem.numero |
Número sequencial da comanda. |
pesagem.codigo |
Código do produto (usado pelo “I” do código de barras). |
pesagem.data |
Data e hora da pesagem. |
pesagem.descricao |
Descrição do preço/produto pesado. |
pesagem.modalidade |
Forma de cobrança. |
pesagem.valor_unitario |
Valor do quilo (por quilo) ou da unidade (fixo) aplicado. |
pesagem.peso_aferido |
Peso lido na balança (kg). |
pesagem.quantidade |
Quantidade cobrada: kg (por quilo, já com a política à vontade) ou unidades (preço fixo). |
pesagem.total |
Valor cobrado (valor unitário × quantidade, já truncado/arredondado pelo app). |
preco.titulo |
Nome do preço (ex.: “Refeição”). |
preco.modalidade |
Forma de cobrança do preço. |
preco.padrao |
Preço padrão da balança (usado quando nenhum outro é escolhido). |
preco.utilizar_politica_avontade |
Aplica a política “à vontade”: a cobrança fica limitada ao valor do à vontade. |
preco.valor_vigente |
Valor do quilo (ou valor fixo) vigente agora. |
preco.valor_avontade |
Valor “à vontade” vigente agora (0 quando não se aplica). |
preco_atual |
Valor do quilo vigente (preço do dia/horário); sem preço usa o valor unitário da pesagem. |
total |
Peso aferido × valor do quilo vigente (sem truncamento). O valor cobrado é pesagem.total. |
exibir_frase |
Verdadeiro quando a configuração exibe frases e há uma frase com texto. |
exibir_mensagem_rodape |
Verdadeiro quando há mensagem de rodapé configurada. |
linhas_em_branco[] |
[1..N] para repetir linhas em branco: {{ for linha in linhas_em_branco }}. N limitado a 0–20. |
codigo_barras |
Conteúdo do código de barras (12 caracteres) montado pelo modelo do código; nulo quando desativado ou quando o template do código é inválido. |
comanda_livre |
Comanda livre (em branco): quantidade, peso aferido e total zerados. |
gratis |
Houve peso aferido, mas o valor cobrado é zero. |
modalidade_por_quilo |
Verdadeiro quando a pesagem é cobrada por quilo (e não por valor fixo). |
produtos_adicionais |
Lista. Produtos adicionais, na ordem cadastrada. |
produtos_adicionais[].ordem |
Posição na lista (ordem crescente). |
produtos_adicionais[].descricao |
Nome do produto. |
produtos_adicionais[].valor_unitario |
Preço unitário (nulo = não impresso). |
produtos_adicionais_agrupados_por_dois |
Lista. Produtos adicionais em grupos de 2; o último grupo é completado com itens vazios. |
produtos_adicionais_agrupados_por_dois[][].descricao |
Nome do produto (nulo no item vazio). |
produtos_adicionais_agrupados_por_dois[][].valor_unitario |
Preço unitário (nulo quando não informado ou no item vazio). |
produtos_adicionais_agrupados_por_tres |
Lista. Produtos adicionais em grupos de 3; o último grupo é completado com itens vazios. |
produtos_adicionais_agrupados_por_tres[][].descricao |
Nome do produto (nulo no item vazio). |
produtos_adicionais_agrupados_por_tres[][].valor_unitario |
Preço unitário (nulo quando não informado ou no item vazio). |
Algumas dicas sobre elas:
pesagem.totalé o valor cobrado, já com a política à vontade e o arredondamento configurado. É o valor que você normalmente quer imprimir.- Na política à vontade,
pesagem.descricaojá traz o título do à vontade (por exemplo “Refeição à vontade”),pesagem.quantidadeé 1 epesagem.valor_unitarioé o valor do à vontade. Para mostrar o peso real do prato, usepesagem.peso_aferido. - Na comanda em branco (comanda livre), valores e peso vêm zerados; use
comanda_livrepara esconder esses campos.
Formatação dos valores
Seção intitulada “Formatação dos valores”Para que números, dinheiro e datas saiam no formato brasileiro, passe o valor por uma função com a barra vertical |:
| Função | O que faz |
|---|---|
moeda |
{{ pesagem.total | moeda }} → “R$ 12,34”. |
numero |
{{ pesagem.peso_aferido | numero 3 }} → “0,450”. |
formatar |
Formata datas e números no padrão brasileiro: {{ pesagem.data | formatar "dd/MM/yyyy" }} → “27/09/2026”, {{ pesagem.total | formatar "C2" }} → “R$ 12,34”. |
bruto |
Escreve o valor sem escapar HTML (permite gerar tags a partir de dados). |
Exemplos prontos:
| Você escreve | Sai no papel |
|---|---|
{{ pesagem.total | moeda }} |
R$ 26,95 |
{{ pesagem.peso_aferido | numero 3 }} |
0,450 |
{{ pesagem.quantidade | numero 0 }} |
1 |
{{ pesagem.data | formatar "dd/MM/yyyy HH:mm" }} |
27/09/2026 12:48 |
{{ pesagem.data | formatar "dd/MM/yy" }} |
27/09/26 |
{{ pesagem.data | formatar "HH:mm" }} |
12:48 |
{{ pesagem.data | formatar "dddd" }} |
domingo |
{{ preco_atual | formatar "C2" }} |
R$ 59,90 |
Sem função, uma data sai completa, como 27/09/2026 12:48:30, e um número sai com vírgula decimal, mas sem casas fixas. Prefira sempre formatar.
Condições
Seção intitulada “Condições”Use {{ if ... }} e {{ end }} para imprimir um trecho só em certas situações. {{ else }} define o que sai no caso
contrário, e {{ else if ... }} encadeia mais casos:
{{ if empresa.site }}<p text-center>{{ empresa.site }}</p>{{ end }}
<p>Total: {{ if gratis }}Grátis{{ else }}{{ pesagem.total | moeda }}{{ end }}</p>
{{ if pesagem.peso_aferido > 1 }}<p>Prato caprichado!</p>{{ else if pesagem.peso_aferido > 0.5 }}<p>Bom apetite!</p>{{ end }}- O
!inverte a condição:{{ if !comanda_livre }}imprime tudo, menos na comanda em branco. - Para comparar, use
>,<,>=,<=,==(igual) e!=(diferente). Em números, use ponto como separador decimal dentro das chaves:0.5, e não0,5. - Contam como “falso” as opções desligadas e os dados vazios: sem valor, texto em branco ou lista sem itens. Por isso
{{ if empresa.site }}só imprime quando o site está preenchido. - Números sempre contam como verdadeiro, até o zero. Para testar um valor, compare:
{{ if pesagem.total > 0 }}. - Todo
{{ if }}precisa do seu{{ end }}.
Repetições
Seção intitulada “Repetições”Use {{ for ... in ... }} e {{ end }} para repetir um trecho para cada item de uma lista:
{{ for item in produtos_adicionais }}<p>( ) {{ item.descricao }} {{ if item.valor_unitario }}{{ item.valor_unitario | moeda }}{{ end }}</p>{{ end }}A lista linhas_em_branco existe só para repetir linhas vazias a quantidade de vezes configurada nas
configurações gerais:
{{ for linha in linhas_em_branco }}<p>______________________________</p>{{ end }}Dentro da repetição, for.index dá a posição (começando em 0), for.first é verdadeiro no primeiro item e for.last
no último.
Comentários
Seção intitulada “Comentários”Trechos entre {{# e }} são anotações suas e não são impressos:
{{# Cabeçalho com o nome e o endereço }}Caracteres especiais
Seção intitulada “Caracteres especiais”Os dados são impressos exatamente como foram cadastrados: um nome como “Bar & Grill” sai correto, sem atrapalhar o
layout. Se um dado contiver, de propósito, marcações de layout que devem ser obedecidas, use a função bruto. Isso é
raro e só é necessário em modelos avançados.
A linguagem dos dados segue o padrão Scriban, e as funções prontas dele também funcionam, como
{{ empresa.nome | string.upcase }} para imprimir o nome em maiúsculas.
Parte 2: o layout
Seção intitulada “Parte 2: o layout”Tudo o que é impresso precisa estar dentro de um bloco. Texto solto, fora de um bloco, não é impresso.
| Marcação | O que faz |
|---|---|
<p>texto</p> |
Parágrafo. O texto quebra nas palavras quando não cabe na linha. |
<table>, <tr>, <td> |
Tabela: <table> abre a tabela, cada <tr> é uma linha e cada <td> é uma célula. |
<br/> |
Linha em branco. Dentro de um parágrafo, quebra a linha. |
<hr/> |
Linha separadora, com traços de ponta a ponta. |
<logo/> |
Logo da empresa, cadastrado em Empresa. Sem logo, não imprime nada. |
<bar-code>...</bar-code> |
Código de barras nativo da impressora. |
Marcações que não estão nesta lista (como <div>) são ignoradas, mas o texto dentro delas continua valendo.
Espaços e quebras de linha
Seção intitulada “Espaços e quebras de linha”- Espaços repetidos, tabulações e quebras de linha do texto do modelo viram um único espaço. Para quebrar a linha
dentro de um parágrafo, use
<br/>:<p>Rua das Flores, 120<br/>Centro</p>. - Para manter espaços ou impedir que duas palavras se separem, use
:<p> Recuo de dois espaços</p>. - Letras acentuadas funcionam normalmente. Emojis não existem na impressora e saem como
?.
Tamanho da letra
Seção intitulada “Tamanho da letra”O atributo font-size define o tamanho da letra do bloco inteiro. O tamanho muda quantos caracteres cabem por linha:
| Atributo | Letra | Papel de 80 mm | Papel de 58 mm |
|---|---|---|---|
font-size="small" |
Pequena | 64 caracteres | 42 caracteres |
font-size="normal" |
Normal (padrão) | 48 caracteres | 32 caracteres |
font-size="large" |
Grande: dobro da largura e da altura | 24 caracteres | 16 caracteres |
<p font-size="large" bold text-center>{{ empresa.nome }}</p><p font-size="small">Letra pequena, para textos longos.</p>Na letra grande cabe só metade dos caracteres: um nome comprido quebra em duas linhas.
Negrito, sublinhado e itálico
Seção intitulada “Negrito, sublinhado e itálico”Acrescente o atributo ao bloco (<p>, <table>, <hr/>, <br/>); ele vale para o bloco inteiro:
| Atributo | Efeito |
|---|---|
bold |
Negrito. |
underline |
Sublinhado, inclusive nos espaços da linha. |
italic |
Aparece só na pré-visualização: as impressoras térmicas não imprimem itálico. |
<p bold underline>TOTAL: {{ pesagem.total | moeda }}</p>Alinhamento
Seção intitulada “Alinhamento”| Atributo | Efeito |
|---|---|
text-left |
À esquerda (o padrão do texto). |
text-center |
Centralizado (o padrão do logo e do código de barras). |
text-right |
À direita. |
text-justified |
Preenche a linha inteira, partindo palavras se preciso. |
text-top, text-middle, text-bottom |
Alinhamento vertical dentro de uma célula de altura fixa. |
Também vale a forma align="center" (ou left, right), e valign="top" (ou middle, bottom) para o vertical.
O alinhamento pode ser posto no <p>, na <table>, na <tr> ou na <td>. Na tabela, a linha herda o alinhamento da
tabela e a célula herda o da linha; o mais específico vence:
<table no-border text-right> <tr> <td text-left>Refeição</td> <td>{{ pesagem.total | moeda }}</td> </tr></table>Tabelas
Seção intitulada “Tabelas”As tabelas são o jeito de pôr informações lado a lado na mesma linha.
- As colunas são definidas pela primeira linha (
<tr>). As outras linhas devem ter a mesma quantidade de células. - Não existe mesclagem de células.
- A largura de cada coluna é dada pelo atributo
widthnas células da primeira linha:
Valor de width |
Largura da coluna |
|---|---|
width="10" |
Exatamente 10 caracteres. |
width="auto" |
Do tamanho do maior texto da coluna. |
width="*" |
Divide o espaço que sobra (é o padrão). |
width="2*" |
Recebe o dobro do espaço que sobra de uma coluna *. |
- A altura de uma linha pode ser fixada com
heightna<tr>:height="3"dá 3 linhas de altura. O padrão,auto, cresce conforme o texto. - Se as colunas não couberem no papel, elas são reduzidas aos poucos; o texto quebra dentro da célula.
Exemplo: descrição ocupando o espaço livre e valor à direita, do tamanho do texto:
<table no-border> <tr> <td>{{ pesagem.descricao }}</td> <td width="auto" text-right>{{ pesagem.total | moeda }}</td> </tr></table>As tabelas nascem com todas as bordas, desenhadas com |, - e +. Os parágrafos nascem sem bordas. Para mudar,
use estes atributos na <table> (ou no <p>):
| Atributo | Bordas |
|---|---|
all-borders |
Todas. |
no-border |
Nenhuma. |
inside-borders |
Só as internas, entre linhas e colunas. |
inside-horizontal-border |
Só as linhas horizontais internas. |
inside-vertical-border |
Só as divisões verticais internas. |
outside-borders |
Só o contorno. |
top-border, bottom-border, left-border, right-border |
Uma borda externa. |
header-border |
Uma caixa em volta da primeira linha (o cabeçalho). |
white-space-border |
Bordas de espaço em branco (margem de um caractere). |
white-space-vertical-border |
Separa as colunas com espaço, sem linhas. |
Os atributos são aplicados na ordem em que aparecem, então a ordem importa. Por exemplo,
<table inside-borders top-border bottom-border> tem as bordas internas e as linhas de cima e de baixo; já em
<table bottom-border inside-borders> a linha de baixo é desfeita pelo inside-borders que vem depois.
Para trocar os caracteres das bordas:
| Atributo | O que troca |
|---|---|
border="*" |
Todos os caracteres de borda. |
edge="=" |
As arestas (esquerda, topo, direita e base). |
corner="+" |
Os cantos. |
border-left, border-top, border-right, border-bottom |
Uma aresta. |
border-top-left, border-top-right, border-bottom-right, border-bottom-left |
Um canto. |
pad-value="." |
O caractere que preenche o espaço vazio da célula. |
O pad-value é ótimo para listas de preço com pontilhado:
<table no-border> <tr> <td pad-value=".">{{ pesagem.descricao }}</td> <td width="auto" text-right>{{ pesagem.total | moeda }}</td> </tr></table>Refeição................................R$ 26,95Linha separadora
Seção intitulada “Linha separadora”<hr/> desenha uma linha de traços na largura do papel. Use pad-value para outro caractere:
<hr/><hr pad-value="="/><hr pad-value="*"/><logo/> imprime o logo cadastrado em Empresa, centralizado. Atributos opcionais:
align="left",align="center"oualign="right": posição na linha.widtheheight: tamanho em pontos da impressora (o papel de 80 mm tem cerca de 576 pontos de largura; o de 58 mm, 384). Informando só um dos dois, a proporção da imagem é mantida. O logo nunca passa da largura do papel.
<logo align="center" width="300"/>Código de barras
Seção intitulada “Código de barras”<bar-code> imprime um código de barras com os números abaixo das barras. O normal é usar o código montado nas
configurações gerais, só quando a opção estiver ligada:
{{ if configuracao_comanda.imprimir_codigo_barras }}<bar-code>{{ codigo_barras }}</bar-code>{{ end }}- O tipo é o escolhido nas configurações gerais. Para forçar outro, use
type="ean13"outype="code128". - No EAN-13 são 12 números; a impressora calcula o 13º.
height="80"define a altura, em pontos (de 1 a 255);width="3"define a espessura das barras (de 2 a 6).- Se o conteúdo ficar vazio, nada é impresso.
Erros comuns
Seção intitulada “Erros comuns”| Sintoma | Causa provável |
|---|---|
Erro “Linha X, coluna Y” logo após escrever um {{ if }} ou {{ for }} |
Falta o {{ end }} correspondente, ou há chaves abertas sem fechar. |
| Um dado não aparece | Nome da variável escrito errado (não dá erro, só fica em branco). |
| Um texto não aparece | Texto solto, fora de <p> ou <td>. |
| A tabela ficou com bordas que você não queria | Tabelas nascem com todas as bordas: acrescente no-border. |
| Uma condição com número nunca falha | Números sempre contam como verdadeiro: compare, como em > 0. |
| O itálico não sai no papel | A impressora térmica não tem itálico. |
| Letras trocadas por “?” | Emoji ou caractere que a impressora não tem. |
Exemplo completo: uma comanda simples
Seção intitulada “Exemplo completo: uma comanda simples”Este modelo imprime o logo, o cabeçalho da empresa, o número e a data, o prato com peso e valor, os produtos adicionais, as linhas para anotação, a frase, o rodapé e o código de barras. Copie, cole num modelo novo e adapte.
{{# Cabeçalho }}<logo/><p bold font-size="large" text-center>{{ empresa.nome }}</p><p text-center>{{ empresa.endereco_completo }}<br/>{{ empresa.cidade }} / {{ empresa.estado }}</p>{{ if empresa.possui_algum_contato }}<p text-center>{{ empresa.contato_empresa }}</p>{{ end }}<hr/>
{{# Número e data }}<table no-border> <tr> <td>Comanda N.{{ pesagem.numero }}</td> <td width="auto" text-right>{{ pesagem.data | formatar "dd/MM/yyyy HH:mm" }}</td> </tr></table><hr/>
{{# Prato }}{{ if comanda_livre }}<p>Comanda livre</p>{{ else }}<p bold>{{ pesagem.descricao }}</p>{{ if modalidade_por_quilo }}<p>{{ pesagem.quantidade | numero 3 }} kg x {{ pesagem.valor_unitario | moeda }}/kg</p>{{ end }}<p bold font-size="large" text-right>{{ if gratis }}Grátis{{ else }}{{ pesagem.total | moeda }}{{ end }}</p>{{ end }}
{{# Produtos adicionais e linhas para anotação }}<table inside-horizontal-border top-border bottom-border> <tr> <td>Adicionais</td> <td width="12" text-right>Valor</td> </tr> {{ for item in produtos_adicionais }} <tr> <td>{{ item.descricao }}</td> <td text-right>{{ if item.valor_unitario }}{{ item.valor_unitario | moeda }}{{ end }}</td> </tr> {{ end }} {{ for linha in linhas_em_branco }} <tr> <td></td> <td></td> </tr> {{ end }}</table>
{{# Frase, rodapé e código de barras }}{{ if exibir_frase }}<br/><p font-size="small" text-center>"{{ frase.descricao }}"</p><p font-size="small" bold text-center>{{ frase.autor }}</p>{{ end }}{{ if exibir_mensagem_rodape }}<br/><p text-center>{{ configuracao_comanda.mensagem_rodape }}</p>{{ end }}{{ if configuracao_comanda.imprimir_codigo_barras }}<br/><bar-code>{{ codigo_barras }}</bar-code>{{ end }}<br/>