Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e57d30863 | |||
| 7a93a30c22 | |||
| 230304e878 | |||
| d185f82bd5 | |||
| 2253d45d00 | |||
| 60e15dbed3 | |||
| 53767df80c |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -122,7 +122,6 @@ impl ReciboData {
|
|||||||
|
|
||||||
// Corta papel
|
// Corta papel
|
||||||
out.extend(escpos::FEED_CUT);
|
out.extend(escpos::FEED_CUT);
|
||||||
out.extend(escpos::CUT);
|
|
||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|||||||
+279
-49
@@ -1022,7 +1022,9 @@ function init() {
|
|||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split('T')[0];
|
||||||
setVal('f-data', today);
|
setVal('f-data', today);
|
||||||
estado.data = today;
|
estado.data = today;
|
||||||
setVal('f-loja', estado.loja);
|
setVal('f-loja', estado.loja || 'União');
|
||||||
|
setVal('f-operador', estado.operador || '');
|
||||||
|
setVal('f-turno', estado.turno || '');
|
||||||
syncHeader();
|
syncHeader();
|
||||||
PRE_FILL_TABLES.forEach(ensureOneRow);
|
PRE_FILL_TABLES.forEach(ensureOneRow);
|
||||||
Object.keys(TABLES).forEach(renderTable);
|
Object.keys(TABLES).forEach(renderTable);
|
||||||
@@ -1045,7 +1047,6 @@ function buildEstadoForBackend() {
|
|||||||
saldo_troco: parseNum(val('sys-troco')), // troco do sistema
|
saldo_troco: parseNum(val('sys-troco')), // troco do sistema
|
||||||
saldo_esperado: parseNum(val('f-saldo-esperado')),
|
saldo_esperado: parseNum(val('f-saldo-esperado')),
|
||||||
fechamento: parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber')),
|
fechamento: parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber')),
|
||||||
diferenca: parseNum(val('f-saldo-esperado')) - (parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber'))),
|
|
||||||
despesas: estado.despesas.map(r => ({ desc: r.desc || '', obs: r.obs || '', valor: r.valor || 0 })),
|
despesas: estado.despesas.map(r => ({ desc: r.desc || '', obs: r.obs || '', valor: r.valor || 0 })),
|
||||||
sangrias: estado.sangrias.map(r => ({ hora: r.hora || '', retirada: r.retirada || 0, gerente: r.gerente || '' })),
|
sangrias: estado.sangrias.map(r => ({ hora: r.hora || '', retirada: r.retirada || 0, gerente: r.gerente || '' })),
|
||||||
pixcnpj: estado.pixcnpj.map(r => ({ nome: r.nome || '', valor: r.valor || 0 })),
|
pixcnpj: estado.pixcnpj.map(r => ({ nome: r.nome || '', valor: r.valor || 0 })),
|
||||||
@@ -1083,8 +1084,44 @@ function loadState() {
|
|||||||
const raw = localStorage.getItem(LS_KEY);
|
const raw = localStorage.getItem(LS_KEY);
|
||||||
if (!raw) return false;
|
if (!raw) return false;
|
||||||
const saved = JSON.parse(raw);
|
const saved = JSON.parse(raw);
|
||||||
// Merge carefully (cartoes may be in old format)
|
// Restore simple fields
|
||||||
Object.assign(estado, saved);
|
estado.uuid = saved.uuid || estado.uuid;
|
||||||
|
estado.id_local = saved.id_local !== undefined ? saved.id_local : null;
|
||||||
|
estado.loja = saved.loja || estado.loja;
|
||||||
|
estado.data = saved.data || estado.data;
|
||||||
|
estado.operador = saved.operador || estado.operador;
|
||||||
|
estado.turno = saved.turno || estado.turno;
|
||||||
|
estado.saldo_troco = saved.saldo_troco || 0;
|
||||||
|
estado.saldo_esperado = saved.saldo_esperado || 0;
|
||||||
|
estado.fechamento = saved.fechamento || 0;
|
||||||
|
estado.observacoes = saved.observacoes || '';
|
||||||
|
estado.sync_status = saved.sync_status || 'local';
|
||||||
|
// Restore tables (always as arrays of objects)
|
||||||
|
estado.despesas = Array.isArray(saved.despesas) ? saved.despesas : [];
|
||||||
|
estado.sangrias = Array.isArray(saved.sangrias) ? saved.sangrias : [];
|
||||||
|
estado.pixcnpj = Array.isArray(saved.pixcnpj) ? saved.pixcnpj : [];
|
||||||
|
estado.vales = Array.isArray(saved.vales) ? saved.vales : [];
|
||||||
|
estado.receber = Array.isArray(saved.receber) ? saved.receber : [];
|
||||||
|
estado.cancelamentos = Array.isArray(saved.cancelamentos) ? saved.cancelamentos : [];
|
||||||
|
// Restore cartoes — each entry must be { valor: number }
|
||||||
|
if (saved.cartoes) {
|
||||||
|
estado.cartoes.credito = Array.isArray(saved.cartoes.credito)
|
||||||
|
? saved.cartoes.credito.map(v => ({ valor: typeof v === 'object' && v !== null ? (v.valor || 0) : (parseNum(v) || 0) }))
|
||||||
|
: [];
|
||||||
|
estado.cartoes.debito = Array.isArray(saved.cartoes.debito)
|
||||||
|
? saved.cartoes.debito.map(v => ({ valor: typeof v === 'object' && v !== null ? (v.valor || 0) : (parseNum(v) || 0) }))
|
||||||
|
: [];
|
||||||
|
estado.cartoes.alimentacao = Array.isArray(saved.cartoes.alimentacao)
|
||||||
|
? saved.cartoes.alimentacao.map(v => ({ valor: typeof v === 'object' && v !== null ? (v.valor || 0) : (parseNum(v) || 0) }))
|
||||||
|
: [];
|
||||||
|
estado.cartoes.pix = Array.isArray(saved.cartoes.pix)
|
||||||
|
? saved.cartoes.pix.map(v => ({ valor: typeof v === 'object' && v !== null ? (v.valor || 0) : (parseNum(v) || 0) }))
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
// Restore fechamento_contado
|
||||||
|
if (saved.fechamento_contado) {
|
||||||
|
estado.fechamento_contado = saved.fechamento_contado;
|
||||||
|
}
|
||||||
setVal('f-data', estado.data || '');
|
setVal('f-data', estado.data || '');
|
||||||
setVal('f-operador', estado.operador || '');
|
setVal('f-operador', estado.operador || '');
|
||||||
setVal('f-turno', estado.turno || '');
|
setVal('f-turno', estado.turno || '');
|
||||||
@@ -1092,9 +1129,10 @@ function loadState() {
|
|||||||
setVal('f-obs', estado.observacoes || '');
|
setVal('f-obs', estado.observacoes || '');
|
||||||
setVal('f-saldo-esperado', estado.saldo_esperado === 0 ? '' : fmtNum(estado.saldo_esperado));
|
setVal('f-saldo-esperado', estado.saldo_esperado === 0 ? '' : fmtNum(estado.saldo_esperado));
|
||||||
setVal('sys-troco', estado.saldo_troco === 0 ? '' : fmtNum(estado.saldo_troco));
|
setVal('sys-troco', estado.saldo_troco === 0 ? '' : fmtNum(estado.saldo_troco));
|
||||||
setVal('f-fech-dinheiro', estado.fechamento_contado && estado.fechamento_contado.dinheiro ? fmtNum(estado.fechamento_contado.dinheiro) : '');
|
const fc = estado.fechamento_contado || {};
|
||||||
setVal('f-fech-cartoes', estado.fechamento_contado && estado.fechamento_contado.cartoes ? fmtNum(estado.fechamento_contado.cartoes) : '');
|
setVal('f-fech-dinheiro', fc.dinheiro ? fmtNum(fc.dinheiro) : '');
|
||||||
setVal('f-fech-receber', estado.fechamento_contado && estado.fechamento_contado.receber ? fmtNum(estado.fechamento_contado.receber) : '');
|
setVal('f-fech-cartoes', fc.cartoes ? fmtNum(fc.cartoes) : '');
|
||||||
|
setVal('f-fech-receber', fc.receber ? fmtNum(fc.receber) : '');
|
||||||
syncHeader();
|
syncHeader();
|
||||||
PRE_FILL_TABLES.forEach(ensureOneRow);
|
PRE_FILL_TABLES.forEach(ensureOneRow);
|
||||||
Object.keys(TABLES).forEach(renderTable);
|
Object.keys(TABLES).forEach(renderTable);
|
||||||
@@ -1191,6 +1229,145 @@ async function tauriEnviar() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Print Preview Window ──────────────────────────────────────────────────
|
||||||
|
function buildPrintHTML(data) {
|
||||||
|
const fmt = v => 'R$ ' + (v || 0).toFixed(2).replace('.', ',');
|
||||||
|
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');
|
||||||
|
|
||||||
|
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;
|
||||||
|
// 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>`; });
|
||||||
|
}
|
||||||
|
// 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>`; });
|
||||||
|
}
|
||||||
|
// 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>`;
|
||||||
|
}
|
||||||
|
// Cancelamentos
|
||||||
|
if (cancelTotal > 0) {
|
||||||
|
rows += `<tr><td>Cancelamentos</td><td>${fmt(cancelTotal)}</td><td></td></tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<!DOCTYPE html>
|
||||||
|
<html><head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Relatório 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; }
|
||||||
|
.header { text-align: center; margin-bottom: 8px; }
|
||||||
|
.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; }
|
||||||
|
.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; }
|
||||||
|
@media print { body { margin: 0; } }
|
||||||
|
</style>
|
||||||
|
</head><body>
|
||||||
|
<div class="header">
|
||||||
|
<h1>${data.loja}</h1>
|
||||||
|
<h2>Fechamento de Caixa</h2>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="row"><span>Data:</span><span>${data.data}</span></div>
|
||||||
|
<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>` : ''}
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div class="grand-total">DIFERENÇA: ${diffStr}</div>
|
||||||
|
<div class="footer">Gerado em ${new Date().toLocaleString('pt-BR')}</div>
|
||||||
|
</body></html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openPrintPreview(data) {
|
||||||
|
// Gera HTML e injeta no body de uma div temporária para window.print()
|
||||||
|
const html = buildPrintHTML(data);
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@media print {
|
||||||
|
body { width: 80mm; margin: 0 auto; font-family: 'Courier New', monospace; font-size: 13px; }
|
||||||
|
.no-print { display: none !important; }
|
||||||
|
}
|
||||||
|
.print-actions { position: fixed; top: 10px; right: 10px; z-index: 9999; }
|
||||||
|
.print-actions button { padding: 8px 16px; cursor: pointer; background: #2563eb; color: #fff; border: none; border-radius: 4px; font-size: 14px; }
|
||||||
|
.print-actions button:hover { background: #1d4ed8; }
|
||||||
|
`;
|
||||||
|
const actions = document.createElement('div');
|
||||||
|
actions.className = 'print-actions no-print';
|
||||||
|
actions.innerHTML = '<button onclick="window.print()">🖨️ Imprimir (Ctrl+P)</button>';
|
||||||
|
|
||||||
|
// Guarda conteúdo original
|
||||||
|
const originalBody = document.body.innerHTML;
|
||||||
|
|
||||||
|
document.body.innerHTML = html;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
document.body.insertBefore(actions, document.body.firstChild);
|
||||||
|
|
||||||
|
// Quando fechar print dialog, restaura
|
||||||
|
const onAfterPrint = () => {
|
||||||
|
document.body.innerHTML = originalBody;
|
||||||
|
window.removeEventListener('afterprint', onAfterPrint);
|
||||||
|
// Re-carrega scripts essenciais
|
||||||
|
location.reload();
|
||||||
|
};
|
||||||
|
window.addEventListener('afterprint', onAfterPrint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function triggerWindowPrint() {
|
||||||
|
// Chama window.print() na janela pai (o próprio app)
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Recibo 80mm via Tauri (ESC/POS USB) ─────────────────────────────────
|
||||||
async function tauriRecibo() {
|
async function tauriRecibo() {
|
||||||
// Build flat totals for the Rust ReciboData struct
|
// Build flat totals for the Rust ReciboData struct
|
||||||
const cartCred = estado.cartoes.credito.reduce((s,r) => s+(r.valor||0), 0);
|
const cartCred = estado.cartoes.credito.reduce((s,r) => s+(r.valor||0), 0);
|
||||||
@@ -1206,7 +1383,6 @@ async function tauriRecibo() {
|
|||||||
const fechamentoCounted = parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber'));
|
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 saldoEsp = parseNum(val('f-saldo-esperado'));
|
||||||
const sysTroco = parseNum(val('sys-troco'));
|
const sysTroco = parseNum(val('sys-troco'));
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
uuid: estado.uuid,
|
uuid: estado.uuid,
|
||||||
id_local: estado.id_local,
|
id_local: estado.id_local,
|
||||||
@@ -1217,15 +1393,8 @@ async function tauriRecibo() {
|
|||||||
saldo_troco: sysTroco,
|
saldo_troco: sysTroco,
|
||||||
saldo_esperado: saldoEsp,
|
saldo_esperado: saldoEsp,
|
||||||
fechamento: fechamentoCounted,
|
fechamento: fechamentoCounted,
|
||||||
diferenca: sysTroco - saldoEsp,
|
diferenca: fechamentoCounted - saldoEsp,
|
||||||
despesas: estado.despesas.map(r => ({ desc: r.desc||'', obs: r.obs||'', valor: r.valor||0 })),
|
// Flat totals for ReciboData struct (Rust) — must be numbers
|
||||||
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||'' })),
|
|
||||||
cartoes: { credito: cartCred, debito: cartDeb, alimentacao: cartAli, pix: cartPix },
|
|
||||||
// Flat totals for ReciboData struct (Rust)
|
|
||||||
credito: cartCred,
|
credito: cartCred,
|
||||||
debito: cartDeb,
|
debito: cartDeb,
|
||||||
alimentacao: cartAli,
|
alimentacao: cartAli,
|
||||||
@@ -1236,10 +1405,26 @@ async function tauriRecibo() {
|
|||||||
vales: valesTotal,
|
vales: valesTotal,
|
||||||
areceber: receberTotal,
|
areceber: receberTotal,
|
||||||
cancelamentos: cancelTotal,
|
cancelamentos: cancelTotal,
|
||||||
|
// Full arrays for backend/storage
|
||||||
|
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||'' })),
|
||||||
|
cartoes: { credito: cartCred, debito: cartDeb, alimentacao: cartAli, pix: cartPix },
|
||||||
observacoes: estado.observacoes,
|
observacoes: estado.observacoes,
|
||||||
sync_status: estado.sync_status,
|
sync_status: estado.sync_status,
|
||||||
};
|
};
|
||||||
return await window.__TAURI__.core.invoke('imprimir_recibo', { estado: JSON.stringify(data) });
|
|
||||||
|
// Tenta ESC/POS via Tauri primeiro; se falhar, abre preview
|
||||||
|
try {
|
||||||
|
return await window.__TAURI__.core.invoke('imprimir_recibo', { estado: JSON.stringify(data) });
|
||||||
|
} catch(e) {
|
||||||
|
console.warn('ESC/POS falhou, abrindo preview:', e);
|
||||||
|
openPrintPreview(data);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function tauriCarregarRascunho() {
|
async function tauriCarregarRascunho() {
|
||||||
@@ -1303,19 +1488,34 @@ document.getElementById('confirm-close').addEventListener('click', closeConfirmM
|
|||||||
document.getElementById('confirm-cancel').addEventListener('click', closeConfirmModal);
|
document.getElementById('confirm-cancel').addEventListener('click', closeConfirmModal);
|
||||||
document.getElementById('modal-confirm').addEventListener('click', e => { if (e.target.id === 'modal-confirm') closeConfirmModal(); });
|
document.getElementById('modal-confirm').addEventListener('click', e => { if (e.target.id === 'modal-confirm') closeConfirmModal(); });
|
||||||
|
|
||||||
// Print from confirm modal
|
// Print from confirm modal — abre preview no navegador
|
||||||
document.getElementById('confirm-print').addEventListener('click', async () => {
|
document.getElementById('confirm-print').addEventListener('click', async () => {
|
||||||
closeConfirmModal();
|
closeConfirmModal();
|
||||||
const btn = document.getElementById('btn-recibo');
|
const cartCred = estado.cartoes.credito.reduce((s,r) => s+(r.valor||0), 0);
|
||||||
btn.disabled = true;
|
const cartDeb = estado.cartoes.debito.reduce((s,r) => s+(r.valor||0), 0);
|
||||||
try {
|
const cartAli = estado.cartoes.alimentacao.reduce((s,r) => s+(r.valor||0), 0);
|
||||||
await tauriRecibo();
|
const cartPix = estado.cartoes.pix.reduce((s,r) => s+(r.valor||0), 0);
|
||||||
alert('✅ Impressão enviada!');
|
const cancelTotal = estado.cancelamentos.reduce((s,r) => s+(parseNum(r.valor||0)||0), 0);
|
||||||
} catch(e) {
|
const fechamentoCounted = parseNum(val('f-fech-dinheiro')) + parseNum(val('f-fech-cartoes')) + parseNum(val('f-fech-receber'));
|
||||||
alert('Erro ao imprimir: ' + (e.message || e));
|
const saldoEsp = parseNum(val('f-saldo-esperado'));
|
||||||
} finally {
|
const data = {
|
||||||
btn.disabled = false;
|
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,
|
||||||
|
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||'' })),
|
||||||
|
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 },
|
||||||
|
observacoes: estado.observacoes,
|
||||||
|
};
|
||||||
|
openPrintPreview(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Confirm send
|
// Confirm send
|
||||||
@@ -1328,10 +1528,17 @@ document.getElementById('confirm-send').addEventListener('click', async () => {
|
|||||||
const r = await tauriEnviar();
|
const r = await tauriEnviar();
|
||||||
estado.sync_status = 'synced';
|
estado.sync_status = 'synced';
|
||||||
saveState();
|
saveState();
|
||||||
alert('✅ Enviado com sucesso!');
|
alert('✅ Enviado com sucesso!\n\n📋 Tabela: fechamentos_web\n🌐 Servidor: supabase.ofrangao.com.br\n\nAbra o Supabase Studio para verificar.');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
await tauriSaveLocal();
|
await tauriSaveLocal();
|
||||||
alert('Erro ao enviar: ' + (e.message || e) + '\n(Dados salvos localmente)');
|
const msg = e?.message || e?.toString?.() || String(e);
|
||||||
|
alert(
|
||||||
|
'⚠️ Erro ao enviar para o Supabase.\n\n' +
|
||||||
|
'📋 Tabela: fechamentos_web\n' +
|
||||||
|
'🌐 Servidor: supabase.ofrangao.com.br\n\n' +
|
||||||
|
'O servidor pode estar offline. Dados salvos localmente.\n\n' +
|
||||||
|
'Erro: ' + msg
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
btn.textContent = '💾 Enviar Fechamento';
|
btn.textContent = '💾 Enviar Fechamento';
|
||||||
@@ -1347,10 +1554,13 @@ document.getElementById('btn-recibo').addEventListener('click', async () => {
|
|||||||
const btn = document.getElementById('btn-recibo');
|
const btn = document.getElementById('btn-recibo');
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
try {
|
try {
|
||||||
|
// Tenta ESC/POS primeiro; se falhar, abre preview no navegador
|
||||||
await tauriRecibo();
|
await tauriRecibo();
|
||||||
alert('✅ Impressão enviada!');
|
// Se chegou aqui sem erro, ESC/POS funcionou
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
alert('Erro ao imprimir: ' + (e.message || e));
|
// ESC/POS falhou — openPrintPreview já foi chamado dentro de tauriRecibo
|
||||||
|
// Só mostra alerta se nem o preview abriu
|
||||||
|
console.warn('Recibo:', e);
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
@@ -1365,30 +1575,42 @@ document.getElementById('btn-limpar').addEventListener('click', () => {
|
|||||||
document.getElementById('btn-anterior').addEventListener('click', async () => {
|
document.getElementById('btn-anterior').addEventListener('click', async () => {
|
||||||
const loja = val('f-loja') || 'União';
|
const loja = val('f-loja') || 'União';
|
||||||
|
|
||||||
// Carrega lista de datas recentes do Supabase
|
// Carrega lista de fechamentos recentes do Supabase com uuid
|
||||||
let datas = [];
|
let recentList = [];
|
||||||
try {
|
try {
|
||||||
const lista = await window.__TAURI__.core.invoke('sb_listar_recentes', { loja, limite: 20 });
|
recentList = await window.__TAURI__.core.invoke('sb_listar_recentes', { loja, limite: 20 });
|
||||||
if (lista && lista.length > 0) {
|
|
||||||
// Extrai datas únicas e já ordenadas
|
|
||||||
datas = [...new Set(lista.map(l => l.data).filter(Boolean))].sort().reverse();
|
|
||||||
}
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.warn('sb_listar_recentes falhou:', e);
|
console.warn('sb_listar_recentes falhou:', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extrai datas únicas ordenadas + mapeamento data→id
|
||||||
|
const dateIdMap = {};
|
||||||
|
const dateList = [];
|
||||||
|
if (recentList && recentList.length > 0) {
|
||||||
|
recentList.forEach(item => {
|
||||||
|
if (item.data && !dateIdMap[item.data]) {
|
||||||
|
dateIdMap[item.data] = item.id;
|
||||||
|
dateList.push(item.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dateList.sort().reverse();
|
||||||
|
}
|
||||||
|
|
||||||
let selectedDate = null;
|
let selectedDate = null;
|
||||||
if (datas.length > 0) {
|
let selectedId = null;
|
||||||
// Mostra seletor com as datas disponíveis
|
if (dateList.length > 0) {
|
||||||
const msg = datas.map((d, i) => `${i + 1}) ${d}`).join('\n');
|
const msg = dateList.map((d, i) => `${i + 1}) ${d}`).join('\n');
|
||||||
const escolha = prompt(`Selecione o número do dia anterior:\n${msg}\n\n(Deixe em branco e clique Cancelar para ver só o dia anterior automático)`);
|
const escolha = prompt(`Selecione o número do dia anterior:\n${msg}\n\n(Deixe em branco e clique Cancelar para ver só o dia anterior automático)`);
|
||||||
if (escolha !== null && escolha.trim() !== '') {
|
if (escolha !== null && escolha.trim() !== '') {
|
||||||
const idx = parseInt(escolha) - 1;
|
const idx = parseInt(escolha) - 1;
|
||||||
if (idx >= 0 && idx < datas.length) selectedDate = datas[idx];
|
if (idx >= 0 && idx < dateList.length) {
|
||||||
|
selectedDate = dateList[idx];
|
||||||
|
selectedId = dateIdMap[selectedDate];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se não escolheu data, usa dia anterior automático
|
// Se não escolheu data, usa dia anterior automático (sem id — carrega por data)
|
||||||
if (!selectedDate) {
|
if (!selectedDate) {
|
||||||
const d = new Date(estado.data); d.setDate(d.getDate() - 1);
|
const d = new Date(estado.data); d.setDate(d.getDate() - 1);
|
||||||
selectedDate = d.toISOString().split('T')[0];
|
selectedDate = d.toISOString().split('T')[0];
|
||||||
@@ -1401,11 +1623,19 @@ document.getElementById('btn-anterior').addEventListener('click', async () => {
|
|||||||
estado.id_local = null;
|
estado.id_local = null;
|
||||||
syncHeader();
|
syncHeader();
|
||||||
|
|
||||||
// Tenta Supabase primeiro, senão local
|
// Tenta Supabase primeiro (com id se disponível), senão local
|
||||||
let rascunho = null;
|
let rascunho = null;
|
||||||
try {
|
if (selectedId) {
|
||||||
rascunho = await window.__TAURI__.core.invoke('sb_carregar_rascunho', { loja, data: selectedDate });
|
// Usa sb_buscar_por_id para buscar por id numérico do Supabase
|
||||||
} catch(e) { console.warn('sb_carregar_rascunho falhou:', e); }
|
try {
|
||||||
|
rascunho = await window.__TAURI__.core.invoke('sb_buscar_por_id', { id: selectedId });
|
||||||
|
} catch(e) { console.warn('sb_buscar_por_id falhou:', e); }
|
||||||
|
}
|
||||||
|
if (!rascunho) {
|
||||||
|
try {
|
||||||
|
rascunho = await window.__TAURI__.core.invoke('sb_carregar_rascunho', { loja, data: selectedDate });
|
||||||
|
} catch(e) { console.warn('sb_carregar_rascunho falhou:', e); }
|
||||||
|
}
|
||||||
|
|
||||||
if (!rascunho) {
|
if (!rascunho) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user