diff --git a/web/src/receipt.ts b/web/src/receipt.ts
new file mode 100644
index 0000000..4f1c5d5
--- /dev/null
+++ b/web/src/receipt.ts
@@ -0,0 +1,128 @@
+import { formatBRL } from './utils';
+
+function escapeHtml(s: string): string {
+ return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+}
+
+function calcularTotais(c: any) {
+ const subtotal = c.total || 0;
+ const desconto = c.desconto || 0;
+ const acrescimo = c.acrescimo || 0;
+ const taxaServico = c.taxaServico ? (subtotal - desconto + acrescimo) * 0.1 : 0;
+ const totalFinal = Math.max(subtotal - desconto + acrescimo + taxaServico, 0);
+ const valorPago = c.valorPago || 0;
+ const restante = Math.max(totalFinal - valorPago, 0);
+ return { subtotal, desconto, acrescimo, taxaServico, totalFinal, valorPago, restante };
+}
+
+export function printConta(c: any) {
+ const itens = c.itens ?? [];
+ const { subtotal, desconto, acrescimo, taxaServico, totalFinal, valorPago, restante } = calcularTotais(c);
+
+ const data = new Date(c.criadoEm).toLocaleString('pt-BR');
+ const agora = new Date().toLocaleString('pt-BR');
+
+ const itemRows = itens.map((i: any) => {
+ const nome = escapeHtml(i.produto?.nome ?? 'Item');
+ const sub = formatBRL(i.precoUnitario * i.quantidade);
+ return `
${i.quantidade}x ${nome}${sub}
`;
+ }).join('');
+
+ const obsRows = itens
+ .filter((i: any) => i.observacao)
+ .map((i: any) => `(${escapeHtml(i.observacao)})
`)
+ .join('');
+
+ const totalsRows = `
+ Subtotal${formatBRL(subtotal)}
+ ${desconto > 0 ? `Desconto-${formatBRL(desconto)}
` : ''}
+ ${acrescimo > 0 ? `Acrescimo+${formatBRL(acrescimo)}
` : ''}
+ ${c.taxaServico ? `Taxa de Servico (10%)+${formatBRL(taxaServico)}
` : ''}
+ `;
+
+ const html = `
+
+
+
+Conta - ${escapeHtml(c.identificador)}
+
+
+
+ CAFE EM SATURNO
+ Gastrobar - Conta de Consumo
+
+ Comanda${escapeHtml(c.identificador)}
+ ${c.nomeCliente ? `Cliente${escapeHtml(c.nomeCliente)}
` : ''}
+ Data${data}
+ ${c.usuario?.nome ? `Operador${escapeHtml(c.usuario.nome)}
` : ''}
+
+
+ ITENS CONSUMIDOS
+ ${itemRows || 'Sem itens
'}
+ ${obsRows}
+
+
+ ${totalsRows}
+
+
+
TOTAL${formatBRL(totalFinal)}
+ ${valorPago > 0 ? `
Pago-${formatBRL(valorPago)}
` : ''}
+
+
+ ${restante > 0
+ ? `A PAGAR
+ ${formatBRL(restante)}
`
+ : `PAGO
`}
+
+
+ Impresso em ${agora}
+
+`;
+
+ let iframe = document.getElementById('print-iframe') as HTMLIFrameElement | null;
+ if (!iframe) {
+ iframe = document.createElement('iframe');
+ iframe.id = 'print-iframe';
+ iframe.style.cssText = 'position:absolute;width:0;height:0;border:0;visibility:hidden;';
+ document.body.appendChild(iframe);
+ }
+
+ iframe.onload = () => {
+ const win = iframe?.contentWindow;
+ if (win) {
+ win.focus();
+ win.print();
+ }
+ };
+
+ const doc = iframe.contentDocument;
+ if (!doc) return;
+ doc.open();
+ doc.write(html);
+ doc.close();
+}
diff --git a/web/src/views/orders.ts b/web/src/views/orders.ts
index 6be4e08..52fe929 100644
--- a/web/src/views/orders.ts
+++ b/web/src/views/orders.ts
@@ -1,5 +1,6 @@
import { api } from '../api';
import { renderNavbar, toast, formatBRL, getUser, statusBadge, parseDisplayDate } from '../utils';
+import { printConta } from '../receipt';
let localComandas: any[] = [];
@@ -766,9 +767,15 @@ function bindOrderEvents() {
const acoesContainer = document.getElementById('detalhes-acoes-pagamento')!;
acoesContainer.innerHTML = '';
const canPay = user && ['ADMIN', 'CAIXA'].includes(user.role);
-
+
+ const printBtnHtml = `
+
+ `;
+
if (canPay && c.status !== 'PAGA' && c.status !== 'CANCELADA' && restante > 0) {
- acoesContainer.innerHTML = `
+ acoesContainer.innerHTML = printBtnHtml + `
@@ -796,9 +803,15 @@ function bindOrderEvents() {
}
});
} else if (canPay && c.status === 'PAGA') {
- acoesContainer.innerHTML = `✅ Comanda Paga
`;
+ acoesContainer.innerHTML = printBtnHtml + `✅ Comanda Paga
`;
+ } else {
+ acoesContainer.innerHTML = printBtnHtml;
}
+ document.getElementById('btn-imprimir-conta')?.addEventListener('click', () => {
+ printConta(c);
+ });
+
(document.getElementById('modal-detalhes-comanda') as HTMLElement).style.display = 'flex';
document.querySelector('.detalhes-edit-section')?.classList.remove('expanded');
};