v1.3.14: dia anterior com modal+senha, editing mode PATCH, sys_total sem troco, fórmulas corrigidas, reportHTML
This commit is contained in:
+225
-136
@@ -514,6 +514,12 @@
|
||||
<div id="cfg-vales-list"></div>
|
||||
<button class="btn-add-config" id="cfg-add-vales">+ Adicionar nome</button>
|
||||
</div>
|
||||
<div class="cfg-section">
|
||||
<div class="cfg-section-title">🔐 Senha Admin (editar dias anteriores)</div>
|
||||
<div style="display:flex;gap:6px;margin-top:4px">
|
||||
<input type="password" id="cfg-admin-password" style="flex:1;padding:6px;border:1px solid #ddd;border-radius:4px;font-size:13px" placeholder="Deixe em branco se não quiser senha">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-primary" id="cfg-salvar">Salvar Configuração</button>
|
||||
@@ -561,6 +567,7 @@ let config = {
|
||||
despesas: ['Energia', 'Água', 'Manutenção', 'Limpeza', 'Insumos'],
|
||||
clientes: [], // preenchimento livre — não é datalist fixo
|
||||
vales_nomes: [], // nomes usados em vales ( histórico para autofill)
|
||||
admin_password: '', // senha para editar dias anteriores no Supabase
|
||||
};
|
||||
|
||||
// ─── App State ────────────────────────────────────────────────────────────
|
||||
@@ -1148,6 +1155,7 @@ function loadConfig() {
|
||||
} catch(e) {}
|
||||
}
|
||||
function saveConfig() {
|
||||
config.admin_password = document.getElementById('cfg-admin-password').value.trim();
|
||||
try { localStorage.setItem(CFG_KEY, JSON.stringify(config)); } catch(e) {}
|
||||
buildDatalists();
|
||||
}
|
||||
@@ -1160,6 +1168,7 @@ function openConfig() {
|
||||
renderCfgList('despesas', 'cfg-despesas-list');
|
||||
renderCfgList('clientes', 'cfg-clientes-list');
|
||||
renderCfgList('vales_nomes', 'cfg-vales-list');
|
||||
document.getElementById('cfg-admin-password').value = config.admin_password || '';
|
||||
}
|
||||
function closeConfig() { document.getElementById('modal-config').classList.remove('open'); }
|
||||
function renderCfgList(key, containerId) {
|
||||
@@ -1940,26 +1949,16 @@ document.getElementById('confirm-send').addEventListener('click', async () => {
|
||||
});
|
||||
|
||||
// ─── Buttons ───────────────────────────────────────────────────────────────
|
||||
document.getElementById('btn-enviar').addEventListener('click', () => {
|
||||
console.log('[DEBUG] btn-enviar clicado');
|
||||
const operador = document.getElementById('f-operador')?.value;
|
||||
const turno = document.getElementById('f-turno')?.value;
|
||||
const loja = document.getElementById('f-loja')?.value;
|
||||
console.log('[DEBUG] operador:', operador, 'turno:', turno, 'loja:', loja);
|
||||
openConfirmModal();
|
||||
});
|
||||
document.getElementById('f-obs').addEventListener('input', e => { estado.observacoes = e.target.value; scheduleSave(); });
|
||||
|
||||
document.getElementById('btn-recibo').addEventListener('click', async () => {
|
||||
const btn = document.getElementById('btn-recibo');
|
||||
btn.disabled = true;
|
||||
try {
|
||||
// Tenta ESC/POS primeiro; se falhar, nada acontece visualmente
|
||||
// — siempre abre preview depois para o usuário ver algo
|
||||
await tauriRecibo();
|
||||
} catch(e) {
|
||||
console.warn('ESC/POS falhou:', e);
|
||||
}
|
||||
// Sempre abre preview depois da tentativa ESC/POS
|
||||
try {
|
||||
const data = buildReciboData();
|
||||
openPrintPreview(data, 'recibo');
|
||||
@@ -1974,7 +1973,6 @@ document.getElementById('btn-recibo').addEventListener('click', async () => {
|
||||
document.getElementById('btn-limpar').addEventListener('click', () => {
|
||||
if (!confirm('Limpar rascunho? Esta acção não pode ser revertida.')) return;
|
||||
localStorage.removeItem(LS_KEY);
|
||||
// Reseta estado e re-renderiza sem reload
|
||||
estado = {
|
||||
uuid: crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(),
|
||||
loja: estado.loja, data: estado.data, operador: '', turno: '',
|
||||
@@ -1994,159 +1992,250 @@ document.getElementById('btn-limpar').addEventListener('click', () => {
|
||||
showToast('Rascunho limpo.', 'info');
|
||||
});
|
||||
|
||||
// ─── Dia Anterior — seleção de registro do Supabase ────────────────────────
|
||||
const btnAnterior = document.getElementById('btn-anterior');
|
||||
if (btnAnterior) {
|
||||
btnAnterior.addEventListener('click', async () => {
|
||||
console.log('[DEBUG] btn-anterior clicado');
|
||||
const loja = val('f-loja') || 'União';
|
||||
console.log('[DEBUG] btn-anterior loja:', loja);
|
||||
const hasTauri = !!(window.__TAURI__ && window.__TAURI__.core);
|
||||
|
||||
// Salva rascunho atual antes de tudo
|
||||
if (hasTauri) {
|
||||
try { await window.__TAURI__.core.invoke('salvar_rascunho_local', {}); } catch(e) { console.warn('salvar_rascunho_local:', e); }
|
||||
}
|
||||
|
||||
// Calcula dia anterior
|
||||
const prevDate = new Date(estado.data);
|
||||
prevDate.setDate(prevDate.getDate() - 1);
|
||||
const prevDateStr = prevDate.toISOString().split('T')[0];
|
||||
|
||||
// Confirmação explícita antes de trocar de dia
|
||||
const confirmMsg = `ATENÇÃO: vai carregar o fechamento de ${prevDateStr}.\n\nO formulário atual será LIMPO caso não tenha enviado.\n\nContinuar?`;
|
||||
if (!confirm(confirmMsg)) {
|
||||
console.log('[DEBUG] btn-anterior cancelado pelo usuário');
|
||||
return;
|
||||
}
|
||||
|
||||
// Carrega lista de fechamentos recentes do Supabase com uuid
|
||||
// Pega lista do Supabase
|
||||
let recentList = [];
|
||||
if (hasTauri) {
|
||||
try {
|
||||
recentList = await window.__TAURI__.core.invoke('sb_listar_recentes', { loja, limite: 20 });
|
||||
const loja = val('f-loja') || 'União';
|
||||
recentList = await window.__TAURI__.core.invoke('sb_listar_recentes', { loja, limite: 50 });
|
||||
console.log('[DEBUG] sb_listar_recentes retornou:', recentList?.length, 'itens');
|
||||
} catch(e) {
|
||||
console.warn('sb_listar_recentes falhou:', e);
|
||||
}
|
||||
} else {
|
||||
console.warn('Tauri não disponível, pulando sb_listar_recentes');
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
console.log('[DEBUG] dateList:', dateList);
|
||||
|
||||
let selectedDate = null;
|
||||
let selectedId = null;
|
||||
if (dateList.length > 0) {
|
||||
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)`);
|
||||
if (escolha !== null && escolha.trim() !== '') {
|
||||
const idx = parseInt(escolha) - 1;
|
||||
if (idx >= 0 && idx < dateList.length) {
|
||||
selectedDate = dateList[idx];
|
||||
selectedId = dateIdMap[selectedDate];
|
||||
}
|
||||
}
|
||||
if (!recentList || recentList.length === 0) {
|
||||
alert('Nenhum fechamento encontrado no servidor para esta loja.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Se não escolheu data, usa dia anterior automático (sem id — carrega por data)
|
||||
if (!selectedDate) {
|
||||
selectedDate = prevDateStr;
|
||||
// Mostra modal de seleção com datas
|
||||
buildAnteriorModal(recentList);
|
||||
});
|
||||
}
|
||||
|
||||
// Monta e abre o modal de seleção de dia anterior
|
||||
function buildAnteriorModal(recentList) {
|
||||
// Remove modal anterior
|
||||
const old = document.getElementById('modal-anterior');
|
||||
if (old) document.body.removeChild(old);
|
||||
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'modal-anterior';
|
||||
overlay.style.cssText = `
|
||||
position:fixed;top:0;left:0;right:0;bottom:0;
|
||||
background:rgba(0,0,0,0.6);z-index:99998;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
`;
|
||||
|
||||
const fmtDate = d => {
|
||||
if (!d) return '';
|
||||
const [y,m,day] = d.split('-');
|
||||
return `${day}/${m}/${y}`;
|
||||
};
|
||||
const syncBadge = s => {
|
||||
const colors = { synced: '#2e7d32', local: '#e65100', syncing: '#f57f17', error: '#c0272d' };
|
||||
const labels = { synced: '✓ Sync', local: '⚠ Local', syncing: '⏳ Sync', error: '✗ Erro' };
|
||||
return `<span style="background:${colors[s]||'#888'};color:#fff;padding:1px 5px;border-radius:3px;font-size:10px">${labels[s]||s||'?'}</span>`;
|
||||
};
|
||||
|
||||
const rows = recentList.map((item, i) => `
|
||||
<tr style="cursor:pointer" onclick="selectDiaAnterior(${i})">
|
||||
<td style="padding:6px 8px;border-bottom:1px solid #eee;font-size:12px">${fmtDate(item.data)}</td>
|
||||
<td style="padding:6px 8px;border-bottom:1px solid #eee;font-size:12px">${item.operador||'?'}</td>
|
||||
<td style="padding:6px 8px;border-bottom:1px solid #eee;font-size:12px">${item.turno||'?'}</td>
|
||||
<td style="padding:6px 8px;border-bottom:1px solid #eee;font-size:12px">${syncBadge(item.sync_status)}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
overlay.innerHTML = `
|
||||
<div style="background:#fff;border-radius:10px;padding:20px;max-width:480px;width:90%;max-height:80vh;overflow-y:auto">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">
|
||||
<h2 style="margin:0;font-size:16px">📅 Selecionar Dia Anterior</h2>
|
||||
<button onclick="closeAnteriorModal()" style="background:none;border:none;font-size:18px;cursor:pointer">✕</button>
|
||||
</div>
|
||||
<p style="font-size:12px;color:#666;margin:0 0 10px">Clique em um registro para carregar. Dados do Supabase.</p>
|
||||
<table style="width:100%;border-collapse:collapse">
|
||||
<thead>
|
||||
<tr style="background:#f5f5f5">
|
||||
<th style="padding:6px 8px;text-align:left;font-size:11px;color:#888">DATA</th>
|
||||
<th style="padding:6px 8px;text-align:left;font-size:11px;color:#888">OPERADOR</th>
|
||||
<th style="padding:6px 8px;text-align:left;font-size:11px;color:#888">TURNO</th>
|
||||
<th style="padding:6px 8px;text-align:left;font-size:11px;color:#888">STATUS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>${rows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
window._recentList = recentList;
|
||||
}
|
||||
|
||||
function closeAnteriorModal() {
|
||||
const m = document.getElementById('modal-anterior');
|
||||
if (m) document.body.removeChild(m);
|
||||
window._recentList = null;
|
||||
}
|
||||
|
||||
// Usuário clicou numa linha — pede senha se configurada
|
||||
window.selectDiaAnterior = async function(idx) {
|
||||
const item = window._recentList[idx];
|
||||
if (!item) return;
|
||||
closeAnteriorModal();
|
||||
|
||||
const pw = config.admin_password;
|
||||
if (pw) {
|
||||
const input = prompt('🔐 Digite a senha admin para editar este registro:');
|
||||
if (input !== pw) {
|
||||
alert('Senha incorreta. Acesso negado.');
|
||||
return;
|
||||
}
|
||||
console.log('[DEBUG] selectedDate:', selectedDate, 'selectedId:', selectedId);
|
||||
}
|
||||
|
||||
setVal('f-data', selectedDate);
|
||||
estado.data = selectedDate;
|
||||
estado.uuid = crypto.randomUUID ? crypto.randomUUID() : Date.now().toString();
|
||||
estado.id_local = null;
|
||||
syncHeader();
|
||||
const hasTauri = !!(window.__TAURI__ && window.__TAURI__.core);
|
||||
if (!hasTauri) { alert('Tauri não disponível.'); return; }
|
||||
|
||||
// Tenta Supabase primeiro (com id se disponível), senão local
|
||||
let rascunho = null;
|
||||
if (hasTauri) {
|
||||
if (selectedId) {
|
||||
try {
|
||||
rascunho = await window.__TAURI__.core.invoke('sb_buscar_por_id', { id: selectedId });
|
||||
console.log('[DEBUG] sb_buscar_por_id retornou:', !!rascunho);
|
||||
} 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 });
|
||||
console.log('[DEBUG] sb_carregar_rascunho retornou:', !!rascunho);
|
||||
} catch(e) { console.warn('sb_carregar_rascunho falhou:', e); }
|
||||
}
|
||||
if (!rascunho) {
|
||||
try {
|
||||
rascunho = await window.__TAURI__.core.invoke('carregar_rascunho', { loja, data: selectedDate });
|
||||
console.log('[DEBUG] carregar_rascunho local retornou:', !!rascunho);
|
||||
} catch(e) { console.warn('carregar_rascunho local falhou:', e); }
|
||||
}
|
||||
} else {
|
||||
console.warn('Tauri não disponível, não foi possível carregar rascunho');
|
||||
try {
|
||||
// Primeiro tenta buscar por id (retorna registro completo)
|
||||
let full = null;
|
||||
if (item.id) {
|
||||
try { full = await window.__TAURI__.core.invoke('sb_buscar_por_id', { id: item.id }); } catch(e) {}
|
||||
}
|
||||
// Fallback: buscar por uuid
|
||||
if (!full && item.uuid) {
|
||||
try { full = await window.__TAURI__.core.invoke('sb_buscar_por_uuid', { uuid: item.uuid }); } catch(e) {}
|
||||
}
|
||||
// Último fallback: carregar por loja+data
|
||||
if (!full) {
|
||||
const loja = val('f-loja') || 'União';
|
||||
full = await window.__TAURI__.core.invoke('sb_carregar_rascunho', { loja, data: item.data });
|
||||
}
|
||||
|
||||
if (rascunho) {
|
||||
console.log('[DEBUG] rascunho carregado com sucesso');
|
||||
if (rascunho.operador) { setVal('f-operador', rascunho.operador); estado.operador = rascunho.operador; }
|
||||
if (rascunho.turno) { setVal('f-turno', rascunho.turno); estado.turno = rascunho.turno; }
|
||||
if (rascunho.saldo_troco) setVal('sys-troco', fmtNum(rascunho.saldo_troco));
|
||||
if (rascunho.saldo_esperado) setVal('f-saldo-esperado', fmtNum(rascunho.saldo_esperado));
|
||||
if (rascunho.observacoes) { setVal('f-obs', rascunho.observacoes); estado.observacoes = rascunho.observacoes; }
|
||||
if (rascunho.despesas && Array.isArray(rascunho.despesas)) {
|
||||
estado.despesas = rascunho.despesas.map(d => ({ desc: d.desc || d.descricao || '', obs: d.obs || '', valor: parseNum(d.valor) || 0 }));
|
||||
}
|
||||
if (rascunho.sangrias && Array.isArray(rascunho.sangrias)) {
|
||||
estado.sangrias = rascunho.sangrias.map(s => ({ hora: s.hora || '', retirada: parseNum(s.retirada) || 0, gerente: s.gerente || '' }));
|
||||
}
|
||||
if (rascunho.pixcnpj && Array.isArray(rascunho.pixcnpj)) {
|
||||
estado.pixcnpj = rascunho.pixcnpj.map(p => ({ nome: p.nome || '', valor: parseNum(p.valor) || 0 }));
|
||||
}
|
||||
if (rascunho.vales && Array.isArray(rascunho.vales)) {
|
||||
estado.vales = rascunho.vales.map(v => ({ nome: v.nome || '', obs: v.obs || '', valor: parseNum(v.valor) || 0 }));
|
||||
}
|
||||
if (rascunho.receber && Array.isArray(rascunho.receber)) {
|
||||
estado.receber = rascunho.receber.map(r => ({ nome: r.nome || '', valor: parseNum(r.valor) || 0 }));
|
||||
}
|
||||
if (rascunho.cancelamentos && Array.isArray(rascunho.cancelamentos)) {
|
||||
estado.cancelamentos = rascunho.cancelamentos.map(c => ({ numero: c.numero || '', valor: parseNum(c.valor) || 0, motivo: c.motivo || '' }));
|
||||
}
|
||||
if (rascunho.cartoes) {
|
||||
const norm = (arr) => Array.isArray(arr) ? arr.map(v => ({ valor: (typeof v === 'object' && v !== null) ? (parseNum(v.valor) || 0) : (parseNum(v) || 0) })) : [];
|
||||
estado.cartoes.credito = norm(rascunho.cartoes.credito);
|
||||
estado.cartoes.debito = norm(rascunho.cartoes.debito);
|
||||
estado.cartoes.alimentacao = norm(rascunho.cartoes.alimentacao);
|
||||
estado.cartoes.pix = norm(rascunho.cartoes.pix);
|
||||
}
|
||||
} else {
|
||||
console.log('[DEBUG] nenhum rascunho encontrado para esta data');
|
||||
estado.despesas = []; estado.sangrias = []; estado.pixcnpj = [];
|
||||
estado.vales = []; estado.receber = []; estado.cancelamentos = [];
|
||||
estado.cartoes = { credito: [], debito: [], alimentacao: [], pix: [] };
|
||||
setVal('sys-troco', ''); setVal('f-saldo-esperado', ''); setVal('f-obs', '');
|
||||
if (!full) { alert('Registro não encontrado.'); return; }
|
||||
|
||||
// Aplica dados ao estado
|
||||
if (full.data) { setVal('f-data', full.data); estado.data = full.data; }
|
||||
if (full.operador) { setVal('f-operador', full.operador); estado.operador = full.operador; }
|
||||
if (full.turno) { setVal('f-turno', full.turno); estado.turno = full.turno; }
|
||||
if (full.saldo_troco != null) setVal('sys-troco', fmtNum(full.saldo_troco));
|
||||
if (full.saldo_esperado != null) setVal('f-saldo-esperado', fmtNum(full.saldo_esperado));
|
||||
if (full.observacoes) { setVal('f-obs', full.observacoes); estado.observacoes = full.observacoes; }
|
||||
|
||||
// Tenta carregar campos aninhados do campo "dados" (jsonb)
|
||||
const dados = full.dados || full;
|
||||
if (dados.despesas && Array.isArray(dados.despesas)) {
|
||||
estado.despesas = dados.despesas.map(d => ({ desc: d.desc||d.descricao||'', obs: d.obs||'', valor: parseNum(d.valor)||0 }));
|
||||
}
|
||||
if (dados.sangrias && Array.isArray(dados.sangrias)) {
|
||||
estado.sangrias = dados.sangrias.map(s => ({ hora: s.hora||'', retirada: parseNum(s.retirada)||0, gerente: s.gerente||'' }));
|
||||
}
|
||||
if (dados.pixcnpj && Array.isArray(dados.pixcnpj)) {
|
||||
estado.pixcnpj = dados.pixcnpj.map(p => ({ nome: p.nome||'', valor: parseNum(p.valor)||0 }));
|
||||
}
|
||||
if (dados.vales && Array.isArray(dados.vales)) {
|
||||
estado.vales = dados.vales.map(v => ({ nome: v.nome||'', obs: v.obs||'', valor: parseNum(v.valor)||0 }));
|
||||
}
|
||||
if (dados.receber && Array.isArray(dados.receber)) {
|
||||
estado.receber = dados.receber.map(r => ({ nome: r.nome||'', valor: parseNum(r.valor)||0 }));
|
||||
}
|
||||
if (dados.cancelamentos && Array.isArray(dados.cancelamentos)) {
|
||||
estado.cancelamentos = dados.cancelamentos.map(c => ({ numero: c.numero||'', valor: parseNum(c.valor)||0, motivo: c.motivo||'' }));
|
||||
}
|
||||
if (dados.cartoes) {
|
||||
const norm = arr => Array.isArray(arr) ? arr.map(v => ({ valor: (typeof v === 'object') ? (parseNum(v.valor)||0) : (parseNum(v)||0) })) : [];
|
||||
estado.cartoes.credito = norm(dados.cartoes.credito);
|
||||
estado.cartoes.debito = norm(dados.cartoes.debito);
|
||||
estado.cartoes.alimentacao = norm(dados.cartoes.alimentacao);
|
||||
estado.cartoes.pix = norm(dados.cartoes.pix);
|
||||
}
|
||||
|
||||
estado.sync_status = rascunho ? 'loaded' : 'local';
|
||||
// Marca como modo de edição — ao clicar Enviar vai fazer PATCH, não POST
|
||||
estado.uuid = full.uuid || item.uuid || estado.uuid;
|
||||
estado.id_local = full.id || item.id || null;
|
||||
estado.sync_status = 'editing'; // flag: editar registro existente
|
||||
|
||||
PRE_FILL_TABLES.forEach(ensureOneRow);
|
||||
Object.keys(TABLES).forEach(renderTable);
|
||||
updateTotals();
|
||||
syncUI();
|
||||
scheduleSave();
|
||||
console.log('[DEBUG] btn-anterior concluído');
|
||||
});
|
||||
} else {
|
||||
console.error('[DEBUG] btn-anterior NÃO encontrado no DOM!');
|
||||
|
||||
alert(`✅ Registro carregado!\n\n📅 ${item.data}\n👤 ${item.operador||'?'} — ${item.turno||'?'}\n\nAo clicar "Enviar Fechamento", o registro será ATUALIZADO no Supabase (não criado novamente).`);
|
||||
} catch(e) {
|
||||
console.error('Erro ao carregar registro:', e);
|
||||
alert('Erro ao carregar registro: ' + (e?.message || e));
|
||||
}
|
||||
};
|
||||
|
||||
// Intercepta o envio — se sync_status=editing, faz PATCH
|
||||
const _originalBtnEnviarHandler = () => {
|
||||
const operador = val('f-operador').trim();
|
||||
const turno = val('f-turno').trim();
|
||||
const loja = val('f-loja').trim();
|
||||
if (!operador || !turno || !loja) {
|
||||
alert('⚠️ Preencha Operador, Turno e Loja antes de enviar.');
|
||||
return;
|
||||
}
|
||||
openConfirmModal();
|
||||
};
|
||||
|
||||
// Modifica btn-enviar para detectar modo editing
|
||||
document.getElementById('btn-enviar').replaceWith(
|
||||
Object.assign(document.createElement('button'), {
|
||||
id: 'btn-enviar', className: 'btn', innerHTML: '💾 Enviar Fechamento',
|
||||
onclick() {
|
||||
const operador = val('f-operador').trim();
|
||||
const turno = val('f-turno').trim();
|
||||
const loja = val('f-loja').trim();
|
||||
if (!operador || !turno || !loja) {
|
||||
alert('⚠️ Preencha Operador, Turno e Loja antes de enviar.');
|
||||
return;
|
||||
}
|
||||
if (estado.sync_status === 'editing') {
|
||||
// Confirmação antes de atualizar
|
||||
if (!confirm(`⚠️ ATENÇÃO: vai ATUALIZAR o registro existente no Supabase!\n\nUUID: ${estado.uuid}\n\nContinuar?`)) return;
|
||||
salvarEdicaoSupabase();
|
||||
} else {
|
||||
openConfirmModal();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
async function salvarEdicaoSupabase() {
|
||||
const hasTauri = !!(window.__TAURI__ && window.__TAURI__.core);
|
||||
if (!hasTauri) { alert('Tauri não disponível.'); return; }
|
||||
const btn = document.getElementById('btn-enviar');
|
||||
if (btn) { btn.disabled = true; btn.textContent = '⏳ Salvando...'; }
|
||||
|
||||
try {
|
||||
const data = buildReciboData();
|
||||
// Remove campos que não devem ir no PATCH
|
||||
delete data.uuid;
|
||||
delete data.id_local;
|
||||
const result = await window.__TAURI__.core.invoke('sb_atualizar_fechamento', {
|
||||
uuid: estado.uuid,
|
||||
updates: JSON.stringify(data)
|
||||
});
|
||||
console.log('[DEBUG] sb_atualizar_fechamento result:', result);
|
||||
estado.sync_status = 'synced';
|
||||
saveState();
|
||||
alert('✅ Registro atualizado com sucesso no Supabase!');
|
||||
} catch(e) {
|
||||
console.error('Erro ao atualizar:', e);
|
||||
alert('❌ Erro ao atualizar no Supabase:\n' + (e?.message || e));
|
||||
} finally {
|
||||
if (btn) { btn.disabled = false; btn.textContent = '💾 Enviar Fechamento'; }
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('f-obs').addEventListener('input', e => { estado.observacoes = e.target.value; scheduleSave(); });
|
||||
|
||||
Reference in New Issue
Block a user