diff --git a/src-tauri/src/plugins/printer.rs b/src-tauri/src/plugins/printer.rs index ac469d4..6e79a09 100644 --- a/src-tauri/src/plugins/printer.rs +++ b/src-tauri/src/plugins/printer.rs @@ -88,7 +88,11 @@ pub struct ReciboData { pub saldo_esperado: f64, /// Diferença = fechamento − saldo_esperado pub diferenca: f64, - /// Soma de todas operações creditadas (crédito + débito + alimentação + voucher + pixcnpj) + /// Total do sistema (troco + crédito + débito + alimentação + voucher + pixcnpj + vales + receber) + #[serde(default)] + pub sys_total: f64, + /// Soma de todas operações creditadas (crédito + débito + alimentação + voucher + pixcnpj) — usado no BLACK section como TOTAL + #[serde(default)] pub total_operado: f64, // Totais de cartões pub credito: f64, @@ -131,7 +135,7 @@ impl ReciboData { } /// Gera todos os bytes ESC/POS do recibo 80mm - /// Layout: SANGRIAS → ENTRADAS → DESPESAS → PIX CNPJ → VALES → A RECEBER → CARTÕES → CANCELAMENTOS → TROCO → OBSERVAÇÕES → TOTAL SALDO CAIXA → SALDO ESPERADO → DIFERENÇA + /// Layout: Header → SANGRIAS → DESPESAS → PIX CNPJ → VALES → A RECEBER → CANCELAMENTOS → CARTÕES → TROCO/Saldo Caixa → SALDO ESPERADO → DIFERENÇA pub fn to_escpos(&self) -> Vec { let mut out = Vec::new(); @@ -165,13 +169,6 @@ impl ReciboData { } out.extend(escpos::divider()); - // ── ENTRADAS ── - out.extend(escpos::line_bold("ENTRADAS")); - out.extend(escpos::kv("Saldo Troco:", &self.fmt_money(self.saldo_troco))); - out.extend(escpos::kv("Fechamento:", &self.fmt_money(self.fechamento))); - out.extend(escpos::kv("Saldo Esperado:", &self.fmt_money(self.saldo_esperado))); - out.extend(escpos::divider()); - // ── DESPESAS ── if !self.despesas_arr.is_empty() { out.extend(escpos::line_bold("DESPESAS")); @@ -228,16 +225,7 @@ impl ReciboData { out.extend(escpos::divider()); } - // ── CARTÕES ── - out.extend(escpos::line_bold("CARTOES")); - out.extend(escpos::kv("Credito:", &self.fmt_money(self.credito))); - out.extend(escpos::kv("Debito:", &self.fmt_money(self.debito))); - out.extend(escpos::kv("Alimentacao:", &self.fmt_money(self.alimentacao))); - out.extend(escpos::kv("PIX Cartao:", &self.fmt_money(self.voucher))); - out.extend(escpos::kv("Cancelamentos:", &self.fmt_money(self.cancelamentos))); - out.extend(escpos::divider()); - - // ── CANCELAMENTOS (detalhe) ── + // ── CANCELAMENTOS ── if !self.cancelamentos_arr.is_empty() { out.extend(escpos::line_bold("CANCELAMENTOS")); for linha in &self.cancelamentos_arr { @@ -254,11 +242,49 @@ impl ReciboData { out.extend(escpos::divider()); } - // ── TROCO ── - out.extend(escpos::line_bold("TROCO")); - out.extend(escpos::kv("Troco:", &self.fmt_money(self.saldo_troco))); + // ── CARTÕES ── + out.extend(escpos::line_bold("CARTOES")); + out.extend(escpos::kv("Credito:", &self.fmt_money(self.credito))); + out.extend(escpos::kv("Debito:", &self.fmt_money(self.debito))); + out.extend(escpos::kv("Alimentacao:", &self.fmt_money(self.alimentacao))); + out.extend(escpos::kv("PIX Cartao:", &self.fmt_money(self.voucher))); + out.extend(escpos::kv("Cancelamentos:", &self.fmt_money(self.cancelamentos))); out.extend(escpos::divider()); + // ── TROCO / SALDO DE CAIXA ── + out.extend(escpos::line_bold("SALDO DE CAIXA")); + out.extend(escpos::kv("Troco (+):", &self.fmt_money(self.saldo_troco))); + out.extend(escpos::kv("Credito (+):", &self.fmt_money(self.credito))); + out.extend(escpos::kv("Debito (+):", &self.fmt_money(self.debito))); + out.extend(escpos::kv("Alimentacao (+):", &self.fmt_money(self.alimentacao))); + out.extend(escpos::kv("PIX Cartao (+):", &self.fmt_money(self.voucher))); + out.extend(escpos::kv("Vales (+):", &self.fmt_money(self.vales))); + out.extend(escpos::kv("A Receber (+):", &self.fmt_money(self.areceber))); + out.extend(escpos::kv("PIX CNPJ (+):", &self.fmt_money(self.pixcnpj))); + out.extend(escpos::divider()); + + // ── TOTAL ── + if self.sys_total > 0.0 { + out.extend(escpos::line_bold("TOTAL")); + out.extend(escpos::kv("Total:", &self.fmt_money(self.sys_total))); + out.extend(escpos::divider()); + } + + // ── SALDO ESPERADO ── + out.extend(escpos::line_bold("SALDO ESPERADO")); + out.extend(escpos::kv("Esperado:", &self.fmt_money(self.saldo_esperado))); + out.extend(escpos::divider()); + + // ── DIFERENÇA ── + out.extend(escpos::line_bold("DIFERENCA")); + let diff = self.sys_total - self.saldo_esperado; + let diff_str = if diff >= 0.0 { + format!("+{}", self.fmt_money(diff)) + } else { + self.fmt_money(diff) + }; + out.extend(escpos::title(&diff_str)); + // ── OBSERVAÇÕES ── if let Some(ref obs) = self.observacoes { if !obs.trim().is_empty() { @@ -268,26 +294,6 @@ impl ReciboData { } } - // ── TOTAL SALDO CAIXA ── - out.extend(escpos::line_bold("TOTAL SALDO DE CAIXA")); - out.extend(escpos::kv("Total:", &self.fmt_money(self.fechamento))); - out.extend(escpos::divider()); - - // ── SALDO ESPERADO ── - out.extend(escpos::line_bold("SALDO ESPERADO")); - out.extend(escpos::kv("Esperado:", &self.fmt_money(self.saldo_esperado))); - out.extend(escpos::divider()); - - // ── DIFERENÇA ── - out.extend(escpos::line_bold("DIFERENCA")); - let diff = self.fechamento - self.saldo_esperado; - let diff_str = if diff >= 0.0 { - format!("+{}", self.fmt_money(diff)) - } else { - self.fmt_money(diff) - }; - out.extend(escpos::title(&diff_str)); - // Rodapé out.extend(escpos::divider()); out.extend(escpos::line_center( diff --git a/src/index.html b/src/index.html index 0ee7348..14a8a1c 100644 --- a/src/index.html +++ b/src/index.html @@ -1229,10 +1229,68 @@ async function tauriEnviar() { } } +function buildConfirmHTML(data) { + const fmt = v => 'R$ ' + (v || 0).toFixed(2).replace('.', ','); + const sangrias = (data.sangrias_arr || data.sangrias || []).reduce((s,r) => s+(parseNum(r.retirada||r.valor||0)||0), 0); + const despesas = (data.despesas_arr || data.despesas || []).reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); + const vales = (data.vales_arr || data.vales || []).reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); + const receber = (data.receber_arr || data.receber || []).reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); + const pixcnpj = (data.pixcnpj_arr || data.pixcnpj || []).reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); + const cancelamentos = (data.cancelamentos_arr || data.cancelamentos || []).reduce((s,c) => s+(parseNum(c.valor||0)||0), 0); + const cartCred = data.credito || 0; + const cartDeb = data.debito || 0; + const cartAli = data.alimentacao || 0; + const cartPix = data.voucher || data.pix || 0; + const fechamento = data.fechamento || 0; + const saldoEsp = data.saldo_esperado || 0; + const diferenca = fechamento - saldoEsp; + const diffClass = diferenca === 0 ? '#2e7d32' : (diferenca > 0 ? '#e65100' : '#c0272d'); + + return ` + + +Relatório de Fechamento + + +
+

${data.loja}

+

Fechamento de Caixa

+
+
📅 Data: ${data.data}   👤 Operador: ${data.operador}   ⏰ Turno: ${data.turno}
+
+
💸 Sangrias: ${fmt(sangrias)}
+
📝 Despesas: ${fmt(despesas)}
+
💰 Vales: ${fmt(vales)}
+
👥 À Receber: ${fmt(receber)}
+
🔵 PIX CNPJ: ${fmt(pixcnpj)}
+
💳 Crédito: ${fmt(cartCred)}
+
💳 Débito: ${fmt(cartDeb)}
+
💳 Alimentação: ${fmt(cartAli)}
+
❌ Cancelamentos: ${fmt(cancelamentos)}
+
📋 Fechamento: ${fmt(fechamento)}
+
+
🎯 Saldo Esperado: ${fmt(saldoEsp)}
+
📐 Diferença: ${fmt(diferenca)}
+
ID: ${data.loja}_${data.data}_${data.operador}
+ +`; +} + // ─── Print Preview Window ────────────────────────────────────────────────── function buildPrintHTML(data) { const fmt = v => 'R$ ' + (v || 0).toFixed(2).replace('.', ','); - const diferenca = (data.fechamento || 0) - (data.total_operado || 0); + const diferenca = (data.fechamento || 0) - (data.saldo_esperado || 0); const diffStr = diferenca >= 0 ? `+${fmt(diferenca)}` : fmt(diferenca); const diffColor = diferenca === 0 ? '#2e7d32' : (diferenca > 0 ? '#e65100' : '#c0272d'); @@ -1307,7 +1365,7 @@ function buildPrintHTML(data) {
ENTRADAS
Saldo Troco:${fmt(data.saldo_troco)}
-
Fechamento:${fmt(data.total_operado || 0)}
+
Fechamento:${fmt(data.fechamento)}
Saldo Esperado:${fmt(data.saldo_esperado)}
${rows ? `
DETALHES
${rows}
` : ''} @@ -1328,7 +1386,8 @@ ${data.observacoes ? `
Obs: ${data.observacoes}
` : ''} `; } -function openPrintPreview(data) { +function openPrintPreview(data, mode) { + const html = mode === 'confirm' ? buildConfirmHTML(data) : buildPrintHTML(data); // Remove preview anterior se existir const existing = document.getElementById('print-preview-overlay'); if (existing) document.body.removeChild(existing); @@ -1362,7 +1421,6 @@ function openPrintPreview(data) { `; - const html = buildPrintHTML(data); const fullHtml = `Recibo${previewStyle}${html}`; const iframe = document.createElement('iframe'); @@ -1423,9 +1481,8 @@ async function tauriRecibo() { const cancelTotal = estado.cancelamentos.reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); const fechamentoCounted = parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber')); const saldoEsp = parseNum(val('f-saldo-esperado')); - const sysTroco = parseNum(val('sys-troco')); - // total_operado = soma de todas operações creditadas (não é o fechamento contado) - const totalOperado = cartCred + cartDeb + cartAli + cartPix + pixCnpjTotal; + // SYS total = troco + crédito + débito + alimentação + vales + receber + pixCartão + pixCnpj + const sysTotal = parseNum(val('sys-troco')) + cartCred + cartDeb + cartAli + valesTotal + receberTotal + cartPix + pixCnpjTotal; const data = { uuid: estado.uuid, id_local: estado.id_local, @@ -1433,11 +1490,11 @@ async function tauriRecibo() { data: estado.data, operador: estado.operador, turno: estado.turno, - saldo_troco: sysTroco, + saldo_troco: parseNum(val('sys-troco')), saldo_esperado: saldoEsp, fechamento: fechamentoCounted, - diferenca: fechamentoCounted - saldoEsp, - total_operado: totalOperado, + diferenca: sysTotal - saldoEsp, + sys_total: sysTotal, // Flat totals for ReciboData struct (Rust) — must be numbers credito: cartCred, debito: cartDeb, @@ -1502,7 +1559,7 @@ function openConfirmModal() { const pixcnpj = estado.pixcnpj.reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); const fechamento = parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber')); const saldoEsp = parseNum(val('f-saldo-esperado')); - const diferenca = fechamento - saldoEsp; + const diferenca = (parseNum(val('sys-troco')) || 0) - saldoEsp; const diffClass = diferenca === 0 ? '#2e7d32' : (diferenca > 0 ? '#e65100' : '#c0272d'); document.getElementById('confirm-summary').innerHTML = `
📅 Data: ${estado.data}   👤 Operador: ${operador}   ⏰ Turno: ${turno}   🏪 Loja: ${loja}
@@ -1532,36 +1589,32 @@ document.getElementById('confirm-close').addEventListener('click', closeConfirmM document.getElementById('confirm-cancel').addEventListener('click', closeConfirmModal); document.getElementById('modal-confirm').addEventListener('click', e => { if (e.target.id === 'modal-confirm') closeConfirmModal(); }); -// Print from confirm modal — abre preview no navegador +// Print from confirm modal — abre preview idêntico ao modal de confirmação document.getElementById('confirm-print').addEventListener('click', async () => { closeConfirmModal(); const cartCred = estado.cartoes.credito.reduce((s,r) => s+(r.valor||0), 0); const cartDeb = estado.cartoes.debito.reduce((s,r) => s+(r.valor||0), 0); const cartAli = estado.cartoes.alimentacao.reduce((s,r) => s+(r.valor||0), 0); const cartPix = estado.cartoes.pix.reduce((s,r) => s+(r.valor||0), 0); - const cancelTotal = estado.cancelamentos.reduce((s,r) => s+(parseNum(r.valor||0)||0), 0); const fechamentoCounted = parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber')); const saldoEsp = parseNum(val('f-saldo-esperado')); - const totalOperado = cartCred + cartDeb + cartAli + cartPix + (estado.pixcnpj.reduce((s,r) => s+(parseNum(r.valor||0)||0), 0)); const data = { loja: estado.loja, data: estado.data, operador: estado.operador, turno: estado.turno, saldo_troco: parseNum(val('sys-troco')) || 0, saldo_esperado: saldoEsp, fechamento: fechamentoCounted, diferenca: fechamentoCounted - saldoEsp, - total_operado: totalOperado, - despesas: estado.despesas.map(r => ({ desc: r.desc||'', obs: r.obs||'', valor: r.valor||0 })), - sangrias: estado.sangrias.map(r => ({ hora: r.hora||'', retirada: parseNum(r.retirada)||0, gerente: r.gerente||'' })), - pixcnpj: estado.pixcnpj.map(r => ({ nome: r.nome||'', valor: r.valor||0 })), - vales: estado.vales.map(r => ({ nome: r.nome||'', obs: r.obs||'', valor: r.valor||0 })), - receber: estado.receber.map(r => ({ nome: r.nome||'', valor: r.valor||0 })), - cancelamentos: estado.cancelamentos.map(r => ({ numero: r.numero||'', valor: r.valor||0, motivo: r.motivo||'' })), + despesas_arr: estado.despesas.map(r => ({ desc: r.desc||'', obs: r.obs||'', valor: r.valor||0 })), + sangrias_arr: estado.sangrias.map(r => ({ hora: r.hora||'', retirada: parseNum(r.retirada)||0, gerente: r.gerente||'' })), + pixcnpj_arr: estado.pixcnpj.map(r => ({ nome: r.nome||'', valor: r.valor||0 })), + vales_arr: estado.vales.map(r => ({ nome: r.nome||'', obs: r.obs||'', valor: r.valor||0 })), + receber_arr: estado.receber.map(r => ({ nome: r.nome||'', valor: r.valor||0 })), + cancelamentos_arr: estado.cancelamentos.map(r => ({ numero: r.numero||'', valor: r.valor||0, motivo: r.motivo||'' })), credito: cartCred, debito: cartDeb, alimentacao: cartAli, - pix: cartPix, // flat float for buildPrintHTML - cartoes: { credito: estado.cartoes.credito, debito: estado.cartoes.debito, alimentacao: estado.cartoes.alimentacao, pix: estado.cartoes.pix }, + voucher: cartPix, observacoes: estado.observacoes, }; - openPrintPreview(data); + openPrintPreview(data, 'confirm'); }); // Confirm send