Compare commits

...

1 Commits

Author SHA1 Message Date
root c01133f39c v1.3.6: nomenclatura trocada; relatórios com todos os lançamentos detalhados por seção
Build Fechamento de Caixa / build (macos-14, app) (push) Has been cancelled
Build Fechamento de Caixa / build (ubuntu-22.04, deb) (push) Has been cancelled
Build Fechamento de Caixa / build (windows-2022, msi) (push) Has been cancelled
2026-06-26 02:52:08 +00:00
+203 -64
View File
@@ -384,7 +384,7 @@
<!-- SALDO DE CAIXA -->
<div class="section">
<div class="section-header">🖥️ Saldo de Caixa (Valores do Sistema)</div>
<div class="section-header">🖥️ Fechamento de Caixa</div>
<div class="sys-grid">
<div class="sys-row"><span class="lbl">Troco (+)</span><input type="text" id="sys-troco" class="editable" placeholder="0,00" /></div>
<div class="sys-row"><span class="lbl">Crédito (+)</span><input type="text" id="sys-credito" readonly tabindex="-1" /></div>
@@ -415,7 +415,7 @@
<!-- FECHAMENTO (VALORES CONTADOS) -->
<div class="section">
<div class="section-header">🛒 Fechamento (Valores Contados)</div>
<div class="section-header">🛒 Saldo de Caixa</div>
<div class="fech-grid">
<div class="fech-item"><div class="fech-item-label">Dinheiro</div><input type="text" id="f-fech-dinheiro" placeholder="0,00" /></div>
<div class="fech-item"><div class="fech-item-label">Cartões</div><input type="text" id="f-fech-cartoes" placeholder="0,00" /></div>
@@ -1231,12 +1231,20 @@ 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 fmtNeg = v => (v < 0 ? '-' : '') + 'R$ ' + Math.abs(v || 0).toFixed(2).replace('.', ',');
const sangrias_arr = data.sangrias_arr || data.sangrias || [];
const despesas_arr = data.despesas_arr || data.despesas || [];
const vales_arr = data.vales_arr || data.vales || [];
const receber_arr = data.receber_arr || data.receber || [];
const pixcnpj_arr = data.pixcnpj_arr || data.pixcnpj || [];
const cancelamentos_arr = data.cancelamentos_arr || data.cancelamentos || [];
const sangrias = sangrias_arr.reduce((s,r) => s+(parseNum(r.retirada)||0)+(parseNum(r.valor)||0), 0);
const despesas = despesas_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const vales = vales_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const receber = receber_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const pixcnpj = pixcnpj_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const cancelamentos = cancelamentos_arr.reduce((s,c) => s+(parseNum(c.valor)||0), 0);
const cartCred = data.credito || 0;
const cartDeb = data.debito || 0;
const cartAli = data.alimentacao || 0;
@@ -1245,6 +1253,79 @@ function buildConfirmHTML(data) {
const saldoEsp = data.saldo_esperado || 0;
const diferenca = fechamento - saldoEsp;
const diffClass = diferenca === 0 ? '#2e7d32' : (diferenca > 0 ? '#e65100' : '#c0272d');
const diffStr = diferenca >= 0 ? `+${fmt(diferenca)}` : fmtNeg(diferenca);
// Monta linhas de detalhe
let detailSections = '';
function detailSection(title, rows, total) {
if (!rows && total <= 0) return '';
let html = `<div class="detail-section"><div class="detail-title">${title}</div>`;
if (rows) html += rows;
html += `<div class="detail-total"><span>Total:</span><span>${fmt(total)}</span></div></div>`;
return html;
}
// Sangrias
let sangriaRows = '';
sangrias_arr.forEach(s => {
const v = (parseNum(s.retirada)||0) + (parseNum(s.valor)||0);
if (v > 0) {
const hora = s.hora ? ` <span class="c2">${s.hora}</span>` : '';
const gerente = s.gerente ? ` <span class="c2">(${s.gerente})</span>` : '';
sangriaRows += `<div class="detail-row"><span>${hora}${gerente}</span><span>${fmt(v)}</span></div>`;
}
});
detailSections += detailSection('SANGRIAS', sangriaRows, sangrias);
// Despesas
let despRows = '';
despesas_arr.forEach(d => {
const v = parseNum(d.valor) || 0;
if (v > 0) {
const obs = d.obs ? ` <span class="c2">${d.obs}</span>` : '';
despRows += `<div class="detail-row"><span>${d.desc||''}${obs}</span><span>${fmt(v)}</span></div>`;
}
});
detailSections += detailSection('DESPESAS', despRows, despesas);
// Vales
let valesRows = '';
vales_arr.forEach(v => {
const val = parseNum(v.valor) || 0;
if (val > 0) {
const obs = v.obs ? ` <span class="c2">${v.obs}</span>` : '';
valesRows += `<div class="detail-row"><span>${v.nome||''}${obs}</span><span>${fmt(val)}</span></div>`;
}
});
detailSections += detailSection('VALES', valesRows, vales);
// A Receber
let recRows = '';
receber_arr.forEach(r => {
const v = parseNum(r.valor) || 0;
if (v > 0) recRows += `<div class="detail-row"><span>${r.nome||''}</span><span>${fmt(v)}</span></div>`;
});
detailSections += detailSection('A RECEBER', recRows, receber);
// PIX CNPJ
let pixRows = '';
pixcnpj_arr.forEach(p => {
const v = parseNum(p.valor) || 0;
if (v > 0) pixRows += `<div class="detail-row"><span>${p.nome||''}</span><span>${fmt(v)}</span></div>`;
});
detailSections += detailSection('PIX CNPJ', pixRows, pixcnpj);
// Cancelamentos
let cancRows = '';
cancelamentos_arr.forEach(c => {
const v = parseNum(c.valor) || 0;
if (c.numero || v > 0) {
const motivo = c.motivo ? ` <span class="c2">${c.motivo}</span>` : '';
cancRows += `<div class="detail-row"><span>${c.numero||''}${motivo}</span><span>${fmt(v)}</span></div>`;
}
});
detailSections += detailSection('CANCELAMENTOS', cancRows, cancelamentos);
return `<!DOCTYPE html>
<html><head>
@@ -1260,6 +1341,11 @@ function buildConfirmHTML(data) {
.row { display: flex; justify-content: space-between; padding: 2px 0; }
.obs { font-size: 11px; color: #555; margin-top: 6px; white-space: pre-wrap; }
.footer { text-align: center; font-size: 11px; color: #555; margin-top: 8px; }
.detail-section { margin: 6px 0; }
.detail-title { font-weight: bold; font-size: 13px; border-top: 1px dashed #b3d9f7; padding-top: 3px; }
.detail-row { display: flex; justify-content: space-between; padding: 1px 0; font-size: 12px; }
.detail-total { display: flex; justify-content: space-between; padding: 1px 0; font-weight: bold; border-top: 1px dotted #b3d9f7; font-size: 12px; }
.c2 { color: #888; }
@media print { body { margin: 0; } }
</style>
</head><body>
@@ -1269,6 +1355,8 @@ function buildConfirmHTML(data) {
</div>
<div style="margin-bottom:6px"><strong>📅 Data:</strong> ${data.data} &nbsp; <strong>👤 Operador:</strong> ${data.operador} &nbsp; <strong>⏰ Turno:</strong> ${data.turno}</div>
<hr>
${detailSections}
<hr>
<div>💸 Sangrias: <strong>${fmt(sangrias)}</strong></div>
<div>📝 Despesas: <strong>${fmt(despesas)}</strong></div>
<div>💰 Vales: <strong>${fmt(vales)}</strong></div>
@@ -1281,59 +1369,115 @@ function buildConfirmHTML(data) {
<div>📋 Fechamento: <strong>${fmt(fechamento)}</strong></div>
<hr>
<div>🎯 Saldo Esperado: <strong>${fmt(saldoEsp)}</strong></div>
<div style="margin-top:4px">📐 Diferença: <strong style="color:${diffClass}">${fmt(diferenca)}</strong></div>
<div style="margin-top:4px">📐 Diferença: <strong style="color:${diffClass}">${diffStr}</strong></div>
<div style="margin-top:4px;font-size:10px;color:#888">ID: ${data.loja}_${data.data}_${data.operador}</div>
<div class="footer">Gerado em ${new Date().toLocaleString('pt-BR')}</div>
</body></html>`;
}
// ─── Print Preview Window ──────────────────────────────────────────────────
// ─── Print Preview Window
function buildPrintHTML(data) {
const fmt = v => 'R$ ' + (v || 0).toFixed(2).replace('.', ',');
// Usa a diferenca ja calculada pelo tauriRecibo (sys_total - saldo_esperado),
// igual ao modal de confirmacao — nao recalcula de fechamento.
const diferenca = data.diferenca !== undefined ? data.diferenca
: ((data.sys_total || 0) - (data.saldo_esperado || 0));
const diffStr = diferenca >= 0 ? `+${fmt(diferenca)}` : fmt(diferenca);
const fmtNeg = v => (v < 0 ? '-' : '') + 'R$ ' + Math.abs(v || 0).toFixed(2).replace('.', ',');
const sangrias_arr = data.sangrias_arr || data.sangrias || [];
const despesas_arr = data.despesas_arr || data.despesas || [];
const vales_arr = data.vales_arr || data.vales || [];
const receber_arr = data.receber_arr || data.receber || [];
const pixcnpj_arr = data.pixcnpj_arr || data.pixcnpj || [];
const cancelamentos_arr = data.cancelamentos_arr || data.cancelamentos || [];
const sangrias = sangrias_arr.reduce((s,r) => s+(parseNum(r.retirada)||0)+(parseNum(r.valor)||0), 0);
const despesas = despesas_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const vales = vales_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const receber = receber_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const pixcnpj = pixcnpj_arr.reduce((s,r) => s+(parseNum(r.valor)||0), 0);
const cancelamentos = cancelamentos_arr.reduce((s,c) => s+(parseNum(c.valor)||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 || data.sys_total || 0;
const saldoEsp = data.saldo_esperado || 0;
const diferenca = data.diferenca !== undefined ? data.diferenca : (fechamento - saldoEsp);
const diffStr = diferenca >= 0 ? `+${fmt(diferenca)}` : fmtNeg(diferenca);
const diffColor = diferenca === 0 ? '#2e7d32' : (diferenca > 0 ? '#e65100' : '#c0272d');
let rows = '';
// Cancelamentos (sum the array first — single cancelamentos is a float total, array is from confirm-print)
const cancelTotal = Array.isArray(data.cancelamentos)
? data.cancelamentos.reduce((s, c) => s + (parseNum(c.valor || 0) || 0), 0)
: (data.cancelamentos || 0);
// PIX total (flat number from tauriRecibo; pixcnpj is also flat total)
const pixTotal = data.pix || data.voucher || 0;
const pixCnpjTotal = typeof data.pixcnpj === 'number' ? data.pixcnpj : 0;
let detailSections = '';
function detailSection(title, rows, total) {
if (!rows && total <= 0) return '';
let html = `<div class="detail-section"><div class="detail-title">${title}</div>`;
if (rows) html += rows;
html += `<div class="detail-total"><span>Total:</span><span>${fmt(total)}</span></div></div>`;
return html;
}
// Sangrias
if (data.sangrias && data.sangrias.length > 0) {
data.sangrias.forEach(s => { if (s.hora || s.retirada) rows += `<tr><td>${s.hora||''}</td><td>${fmt(s.retirada)}</td><td>${s.gerente||''}</td></tr>`; });
let sangriaRows = '';
sangrias_arr.forEach(s => {
const v = (parseNum(s.retirada)||0) + (parseNum(s.valor)||0);
if (v > 0) {
const hora = s.hora ? ` <span class="c2">${s.hora}</span>` : '';
const gerente = s.gerente ? ` <span class="c2">(${s.gerente})</span>` : '';
sangriaRows += `<div class="detail-row"><span>${hora}${gerente}</span><span>${fmt(v)}</span></div>`;
}
});
detailSections += detailSection('SANGRIAS', sangriaRows, sangrias);
// Despesas
if (data.despesas && data.despesas.length > 0) {
data.despesas.forEach(d => { if (d.desc || d.valor) rows += `<tr><td>${d.desc||''}</td><td>${fmt(d.valor)}</td><td>${d.obs||''}</td></tr>`; });
let despRows = '';
despesas_arr.forEach(d => {
const v = parseNum(d.valor) || 0;
if (v > 0) {
const obs = d.obs ? ` <span class="c2">${d.obs}</span>` : '';
despRows += `<div class="detail-row"><span>${d.desc||''}${obs}</span><span>${fmt(v)}</span></div>`;
}
});
detailSections += detailSection('DESPESAS', despRows, despesas);
// Vales
if (data.vales && data.vales.length > 0) {
data.vales.forEach(v => { if (v.nome || v.valor) rows += `<tr><td>${v.nome||''}</td><td>${fmt(v.valor)}</td><td>${v.obs||''}</td></tr>`; });
}
// Receber
if (data.receber && data.receber.length > 0) {
data.receber.forEach(r => { if (r.nome || r.valor) rows += `<tr><td>${r.nome||''}</td><td>${fmt(r.valor)}</td><td></td></tr>`; });
}
// PIX CNPJ (flat total, not array)
if (pixCnpjTotal > 0) {
rows += `<tr><td>PIX CNPJ</td><td>${fmt(pixCnpjTotal)}</td><td></td></tr>`;
let valesRows = '';
vales_arr.forEach(v => {
const val = parseNum(v.valor) || 0;
if (val > 0) {
const obs = v.obs ? ` <span class="c2">${v.obs}</span>` : '';
valesRows += `<div class="detail-row"><span>${v.nome||''}${obs}</span><span>${fmt(val)}</span></div>`;
}
});
detailSections += detailSection('VALES', valesRows, vales);
// A Receber
let recRows = '';
receber_arr.forEach(r => {
const v = parseNum(r.valor) || 0;
if (v > 0) recRows += `<div class="detail-row"><span>${r.nome||''}</span><span>${fmt(v)}</span></div>`;
});
detailSections += detailSection('A RECEBER', recRows, receber);
// PIX CNPJ
let pixRows = '';
pixcnpj_arr.forEach(p => {
const v = parseNum(p.valor) || 0;
if (v > 0) pixRows += `<div class="detail-row"><span>${p.nome||''}</span><span>${fmt(v)}</span></div>`;
});
detailSections += detailSection('PIX CNPJ', pixRows, pixcnpj);
// Cancelamentos
if (cancelTotal > 0) {
rows += `<tr><td>Cancelamentos</td><td>${fmt(cancelTotal)}</td><td></td></tr>`;
let cancRows = '';
cancelamentos_arr.forEach(c => {
const v = parseNum(c.valor) || 0;
if (c.numero || v > 0) {
const motivo = c.motivo ? ` <span class="c2">${c.motivo}</span>` : '';
cancRows += `<div class="detail-row"><span>${c.numero||''}${motivo}</span><span>${fmt(v)}</span></div>`;
}
});
detailSections += detailSection('CANCELAMENTOS', cancRows, cancelamentos);
return `<!DOCTYPE html>
<html><head>
<meta charset="UTF-8">
<title>Relatório de Fechamento</title>
<title>Recibo de Fechamento</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Courier New', monospace; font-size: 13px; width: 80mm; margin: 0 auto; padding: 8px; }
@@ -1341,19 +1485,16 @@ function buildPrintHTML(data) {
.header h1 { font-size: 18px; }
.header h2 { font-size: 14px; font-weight: normal; }
hr { border: none; border-top: 1px dashed #000; margin: 6px 0; }
.section { margin: 6px 0; }
.section-title { font-weight: bold; font-size: 14px; border-top: 1px dashed #000; padding-top: 4px; margin-top: 6px; }
.row { display: flex; justify-content: space-between; padding: 2px 0; }
.row.space-between { justify-content: space-between; }
.row.below { margin-top: 4px; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
td { padding: 2px 4px; vertical-align: top; }
td:nth-child(2) { text-align: right; }
td:nth-child(3) { text-align: right; color: #555; font-size: 11px; }
.total-row { font-weight: bold; border-top: 1px dashed #000; }
.detail-section { margin: 6px 0; }
.detail-title { font-weight: bold; font-size: 13px; border-top: 1px dashed #000; padding-top: 3px; }
.detail-row { display: flex; justify-content: space-between; padding: 1px 0; font-size: 12px; }
.detail-total { display: flex; justify-content: space-between; padding: 1px 0; font-weight: bold; border-top: 1px dotted #000; font-size: 12px; }
.grand-total { font-size: 16px; font-weight: bold; text-align: center; padding: 6px; border: 2px solid #000; margin: 8px 0; }
.obs { font-size: 11px; color: #555; margin-top: 6px; white-space: pre-wrap; }
.footer { text-align: center; font-size: 11px; color: #555; margin-top: 8px; }
.c2 { color: #888; }
@media print { body { margin: 0; } }
</style>
</head><body>
@@ -1366,29 +1507,27 @@ function buildPrintHTML(data) {
<div class="row"><span>Operador:</span><span>${data.operador}</span></div>
<div class="row"><span>Turno:</span><span>${data.turno}</span></div>
<div class="section-title">ENTRADAS</div>
<div class="row"><span>Saldo Troco:</span><span>${fmt(data.saldo_troco)}</span></div>
<div class="row"><span>Fechamento:</span><span>${fmt(data.fechamento)}</span></div>
<div class="row"><span>Saldo Esperado:</span><span>${fmt(data.saldo_esperado)}</span></div>
${rows ? `<div class="section-title">DETALHES</div><table><tbody>${rows}</tbody></table>` : ''}
${data.observacoes ? `<div class="obs">Obs: ${data.observacoes}</div>` : ''}
${detailSections}
<hr>
<div class="section-title">CARTÕES</div>
<div class="row"><span>Crédito:</span><span>${fmt(data.credito||0)}</span></div>
<div class="row"><span>Débito:</span><span>${fmt(data.debito||0)}</span></div>
<div class="row"><span>Alimentação:</span><span>${fmt(data.alimentacao||0)}</span></div>
<div class="row"><span>PIX Cartão:</span><span>${fmt(pixTotal)}</span></div>
<div class="row"><span>Cancelamentos:</span><span>${fmt(cancelTotal)}</span></div>
<div class="row"><span>💸 Sangrias:</span><span>${fmt(sangrias)}</span></div>
<div class="row"><span>📝 Despesas:</span><span>${fmt(despesas)}</span></div>
<div class="row"><span>💰 Vales:</span><span>${fmt(vales)}</span></div>
<div class="row"><span>👥 À Receber:</span><span>${fmt(receber)}</span></div>
<div class="row"><span>🔵 PIX CNPJ:</span><span>${fmt(pixcnpj)}</span></div>
<div class="row"><span>💳 Crédito:</span><span>${fmt(cartCred)}</span></div>
<div class="row"><span>💳 Débito:</span><span>${fmt(cartDeb)}</span></div>
<div class="row"><span>💳 Alimentação:</span><span>${fmt(cartAli)}</span></div>
<div class="row"><span>❌ Cancelamentos:</span><span>${fmt(cancelamentos)}</span></div>
<hr>
<div class="grand-total">DIFERENÇA: ${diffStr}</div>
${data.observacoes ? `<div class="obs">Obs: ${data.observacoes}</div>` : ''}
<div class="footer">Gerado em ${new Date().toLocaleString('pt-BR')}</div>
</body></html>`;
}
}
function openPrintPreview(data, mode) {
const html = mode === 'confirm' ? buildConfirmHTML(data) : buildPrintHTML(data);
// Remove preview anterior se existir