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)} + + + + +
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'); };