Compare commits
2 Commits
b022d09a71
...
b710603876
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b710603876 | ||
|
|
1c8568927c |
@@ -14,9 +14,6 @@ export async function renderPagamentos(container) {
|
|||||||
<div class="page-title">💳 Pagamentos</div>
|
<div class="page-title">💳 Pagamentos</div>
|
||||||
<div class="page-subtitle">Histórico financeiro do estabelecimento</div>
|
<div class="page-subtitle">Histórico financeiro do estabelecimento</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="page-actions">
|
|
||||||
<button class="btn btn-primary btn-md" id="btn-novo-pag">+ Registrar Pagamento</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<div class="table-toolbar">
|
<div class="table-toolbar">
|
||||||
@@ -26,14 +23,37 @@ export async function renderPagamentos(container) {
|
|||||||
${tiposPag.map(t => `<option value="${t.id}">${t.nome || t.name}</option>`).join('')}
|
${tiposPag.map(t => `<option value="${t.id}">${t.nome || t.name}</option>`).join('')}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="table-toolbar" style="border-top:1px solid var(--border);margin-top:0;padding-top:12px">
|
||||||
|
<div style="display:flex;gap:12px;align-items:center;flex-wrap:wrap">
|
||||||
|
<div style="display:flex;gap:8px;align-items:center">
|
||||||
|
<label style="font-size:0.8rem;color:var(--text-muted)">De:</label>
|
||||||
|
<input type="datetime-local" id="filter-dataini" class="form-control" style="width:180px" />
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:8px;align-items:center">
|
||||||
|
<label style="font-size:0.8rem;color:var(--text-muted)">Até:</label>
|
||||||
|
<input type="datetime-local" id="filter-datafim" class="form-control" style="width:180px" />
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="btn-limpar-filtro-data">🗑️ Limpar</button>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:8px">
|
||||||
|
<button class="btn btn-warning btn-md" id="btn-imprimir-relatorio">🖨️ Imprimir Cupom</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="pagamentos-table"></div>
|
<div id="pagamentos-table"></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
await loadPagamentos(tiposPag, comandas, clientes);
|
await loadPagamentos(tiposPag, comandas, clientes);
|
||||||
|
|
||||||
document.getElementById('btn-novo-pag').addEventListener('click', () => abrirModalPagamento(tiposPag, comandas));
|
|
||||||
document.getElementById('search-pag').addEventListener('input', () => filtrarPagamentos());
|
document.getElementById('search-pag').addEventListener('input', () => filtrarPagamentos());
|
||||||
document.getElementById('filter-tipo').addEventListener('change', () => filtrarPagamentos());
|
document.getElementById('filter-tipo').addEventListener('change', () => filtrarPagamentos());
|
||||||
|
document.getElementById('filter-dataini').addEventListener('change', () => filtrarPagamentos());
|
||||||
|
document.getElementById('filter-datafim').addEventListener('change', () => filtrarPagamentos());
|
||||||
|
document.getElementById('btn-limpar-filtro-data').addEventListener('click', () => {
|
||||||
|
document.getElementById('filter-dataini').value = '';
|
||||||
|
document.getElementById('filter-datafim').value = '';
|
||||||
|
filtrarPagamentos();
|
||||||
|
});
|
||||||
|
document.getElementById('btn-imprimir-relatorio').addEventListener('click', () => imprimirRelatorio());
|
||||||
}
|
}
|
||||||
|
|
||||||
let _pagsData = [];
|
let _pagsData = [];
|
||||||
@@ -60,7 +80,8 @@ async function loadPagamentos(tiposPag, comandas, clientes) {
|
|||||||
mesa_name: c.mesa_name || '',
|
mesa_name: c.mesa_name || '',
|
||||||
status: c.status,
|
status: c.status,
|
||||||
dt_open: c.dt_open,
|
dt_open: c.dt_open,
|
||||||
client: c.client
|
client: c.client,
|
||||||
|
user: c.user
|
||||||
};
|
};
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
@@ -72,159 +93,47 @@ async function loadPagamentos(tiposPag, comandas, clientes) {
|
|||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPagsTable();
|
window._pagsFiltered = _pagsData;
|
||||||
}
|
renderPagsTableFiltered(_pagsData);
|
||||||
|
|
||||||
function renderPagsTable() {
|
|
||||||
const wrap = document.getElementById('pagamentos-table');
|
|
||||||
if (!wrap) return;
|
|
||||||
|
|
||||||
if (!_pagsData.length) {
|
|
||||||
wrap.innerHTML = `<div class="table-empty">Nenhum pagamento registrado.</div>`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const total = _pagsData.reduce((acc, p) => acc + parseFloat(p.value || 0), 0);
|
|
||||||
|
|
||||||
wrap.innerHTML = `
|
|
||||||
<table>
|
|
||||||
<thead><tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>Cliente</th>
|
|
||||||
<th>Comanda</th>
|
|
||||||
<th>Tipo</th>
|
|
||||||
<th>Valor</th>
|
|
||||||
<th>Descrição</th>
|
|
||||||
<th>Data</th>
|
|
||||||
<th>Ações</th>
|
|
||||||
</tr></thead>
|
|
||||||
<tbody>
|
|
||||||
${_pagsData.map(p => {
|
|
||||||
const cInfo = _cmdMap[String(p.comanda)];
|
|
||||||
const clienteNome = _clientesMap[String(p.client)] || p.client_name || '–';
|
|
||||||
const cDesc = cInfo ? `${cInfo.name} (${cInfo.mesa})` : (p.comanda_name || '–');
|
|
||||||
return `
|
|
||||||
<tr>
|
|
||||||
<td style="color:var(--text-muted)">#${p.id}</td>
|
|
||||||
<td>${clienteNome}</td>
|
|
||||||
<td>
|
|
||||||
${p.comanda ? `<span style="font-size:0.8rem">
|
|
||||||
<span style="color:var(--text-muted)">#${p.comanda}</span>
|
|
||||||
<span style="color:var(--text-secondary)"> ${cDesc}</span>
|
|
||||||
</span>` : '–'}
|
|
||||||
</td>
|
|
||||||
<td><span class="badge badge-info">${p.type_pay_name || '–'}</span></td>
|
|
||||||
<td><strong style="color:var(--success)">R$ ${parseFloat(p.value || 0).toFixed(2)}</strong></td>
|
|
||||||
<td style="max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-secondary);font-size:0.82rem">
|
|
||||||
${p.description || '–'}
|
|
||||||
</td>
|
|
||||||
<td style="white-space:nowrap;font-size:0.82rem">${formatDate(p.datetime)}</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-secondary btn-sm btn-view-pag" data-id="${p.id}">🔍 Ver</button>
|
|
||||||
</td>
|
|
||||||
</tr>`;
|
|
||||||
}).join('')}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div style="padding:14px 20px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;align-items:center;gap:8px">
|
|
||||||
<span style="font-size:0.82rem;color:var(--text-secondary)">Total exibido:</span>
|
|
||||||
<strong style="color:var(--success);font-size:1rem">R$ ${total.toFixed(2)}</strong>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
wrap.querySelectorAll('.btn-view-pag').forEach(btn =>
|
|
||||||
btn.addEventListener('click', () => {
|
|
||||||
const pag = _pagsData.find(p => String(p.id) === String(btn.dataset.id));
|
|
||||||
if (pag) abrirDetalhesPagamento(pag);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function abrirDetalhesPagamento(pagamento) {
|
|
||||||
const cInfo = _cmdMap[String(pagamento.comanda)];
|
|
||||||
const tipoNome = _tiposPag.find(t => String(t.id) === String(pagamento.type_pay))?.name ||
|
|
||||||
_tiposPag.find(t => String(t.id) === String(pagamento.type_pay))?.nome ||
|
|
||||||
pagamento.type_pay_name || '–';
|
|
||||||
const clienteNome = _clientesMap[String(pagamento.client)] || pagamento.client_name || '–';
|
|
||||||
|
|
||||||
openModal({
|
|
||||||
title: `💳 Detalhes do Pagamento #${pagamento.id}`,
|
|
||||||
body: `
|
|
||||||
<div style="display:flex;flex-direction:column;gap:16px">
|
|
||||||
<div class="card" style="padding:16px;background:var(--bg-elevated)">
|
|
||||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px">
|
|
||||||
<div>
|
|
||||||
<div style="font-size:0.75rem;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Valor</div>
|
|
||||||
<div style="font-size:1.5rem;font-weight:700;color:var(--success)">R$ ${parseFloat(pagamento.value || 0).toFixed(2)}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div style="font-size:0.75rem;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Forma de Pagamento</div>
|
|
||||||
<div style="font-size:1rem;font-weight:600">${tipoNome}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
|
|
||||||
<div>
|
|
||||||
<div style="font-size:0.75rem;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Cliente</div>
|
|
||||||
<div style="font-weight:500">${clienteNome}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div style="font-size:0.75rem;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Data/Hora</div>
|
|
||||||
<div style="font-weight:500">${formatDate(pagamento.datetime)}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${pagamento.comanda ? `
|
|
||||||
<div>
|
|
||||||
<div style="font-size:0.75rem;color:var(--text-muted);text-transform:uppercase;margin-bottom:8px">Comanda</div>
|
|
||||||
<div class="card" style="padding:12px;background:var(--bg-elevated)">
|
|
||||||
<div style="display:flex;justify-content:space-between;margin-bottom:8px">
|
|
||||||
<div>
|
|
||||||
<div style="font-weight:600">#${pagamento.comanda} — ${cInfo?.name || '–'}</div>
|
|
||||||
<div style="font-size:0.8rem;color:var(--text-secondary)">${cInfo?.mesa || '–'}</div>
|
|
||||||
</div>
|
|
||||||
<span class="badge badge-${cInfo?.status === 'FIADO' ? 'warning' : cInfo?.status === 'CLOSED' ? 'success' : 'info'}">
|
|
||||||
${cInfo?.status || '–'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
${cInfo?.dt_open ? `
|
|
||||||
<div style="font-size:0.8rem;color:var(--text-muted)">
|
|
||||||
Abertura: ${formatDate(cInfo.dt_open)}
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
${pagamento.description ? `
|
|
||||||
<div>
|
|
||||||
<div style="font-size:0.75rem;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Descrição</div>
|
|
||||||
<div style="padding:10px;background:var(--bg-elevated);border-radius:var(--radius-sm)">${pagamento.description}</div>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
footer: `<button class="btn btn-secondary btn-md" onclick="closeModal()">Fechar</button>`
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function filtrarPagamentos() {
|
function filtrarPagamentos() {
|
||||||
const q = document.getElementById('search-pag')?.value.toLowerCase() || '';
|
const search = (document.getElementById('search-pag')?.value || '').toLowerCase();
|
||||||
const tipo = parseInt(document.getElementById('filter-tipo')?.value) || null;
|
const tipo = document.getElementById('filter-tipo')?.value || '';
|
||||||
|
const dataIni = document.getElementById('filter-dataini')?.value;
|
||||||
|
const dataFim = document.getElementById('filter-datafim')?.value;
|
||||||
|
|
||||||
const filtered = _pagsData.filter(p => {
|
const filtered = _pagsData.filter(p => {
|
||||||
const clienteNome = _clientesMap[String(p.client)] || p.client_name || '';
|
if (tipo && String(p.type_pay) !== tipo) return false;
|
||||||
const cInfo = _cmdMap[String(p.comanda)];
|
|
||||||
const comandaNome = cInfo?.name || p.comanda_name || '';
|
if (dataIni) {
|
||||||
const matchQ = !q ||
|
const pDate = new Date(p.datetime);
|
||||||
clienteNome.toLowerCase().includes(q) ||
|
const iniDate = new Date(dataIni);
|
||||||
comandaNome.toLowerCase().includes(q) ||
|
if (pDate < iniDate) return false;
|
||||||
(p.description || '').toLowerCase().includes(q) ||
|
}
|
||||||
String(p.id).includes(q);
|
if (dataFim) {
|
||||||
const matchTipo = !tipo || p.type_pay === tipo;
|
const pDate = new Date(p.datetime);
|
||||||
return matchQ && matchTipo;
|
const fimDate = new Date(dataFim);
|
||||||
|
fimDate.setHours(23, 59, 59, 999);
|
||||||
|
if (pDate > fimDate) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
const cInfo = _cmdMap[String(p.comanda)];
|
||||||
|
const clienteNome = _clientesMap[String(p.client)] || p.client_name || '';
|
||||||
|
const cDesc = cInfo ? `${cInfo.name} ${cInfo.mesa}` : (p.comanda_name || '');
|
||||||
|
const searchStr = `${p.id} ${clienteNome} ${p.comanda} ${cDesc} ${p.description} ${p.value}`.toLowerCase();
|
||||||
|
if (!searchStr.includes(search)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window._pagsFiltered = filtered;
|
||||||
|
renderPagsTableFiltered(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagsTableFiltered(filtered) {
|
||||||
const wrap = document.getElementById('pagamentos-table');
|
const wrap = document.getElementById('pagamentos-table');
|
||||||
if (!wrap) return;
|
if (!wrap) return;
|
||||||
|
|
||||||
@@ -288,6 +197,102 @@ function filtrarPagamentos() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function imprimirRelatorio() {
|
||||||
|
const filtered = window._pagsFiltered || _pagsData;
|
||||||
|
if (!filtered.length) return showToast('Nenhum pagamento para imprimir.', 'warning');
|
||||||
|
|
||||||
|
const dataIni = document.getElementById('filter-dataini')?.value;
|
||||||
|
const dataFim = document.getElementById('filter-datafim')?.value;
|
||||||
|
|
||||||
|
const dataIniStr = dataIni ? new Date(dataIni).toLocaleString('pt-BR') : 'Início';
|
||||||
|
const dataFimStr = dataFim ? new Date(dataFim).toLocaleString('pt-BR') : 'Agora';
|
||||||
|
|
||||||
|
const porTipo = {};
|
||||||
|
filtered.forEach(p => {
|
||||||
|
const tipoNome = p.type_pay_name || _tiposPag.find(t => String(t.id) === String(p.type_pay))?.nome || _tiposPag.find(t => String(t.id) === String(p.type_pay))?.name || 'Outro';
|
||||||
|
if (!porTipo[tipoNome]) porTipo[tipoNome] = 0;
|
||||||
|
porTipo[tipoNome] += parseFloat(p.value || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalGeral = filtered.reduce((acc, p) => acc + parseFloat(p.value || 0), 0);
|
||||||
|
|
||||||
|
const htmlRelatorio = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Relatório de Pagamentos</title>
|
||||||
|
<style>
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body { font-family: 'Courier New', monospace; font-size: 12px; padding: 10px; width: 80mm; }
|
||||||
|
.rel { display: block; }
|
||||||
|
.rel * { color: black !important; background: transparent !important; }
|
||||||
|
.header { text-align: center; border-bottom: 2px solid #000; padding-bottom: 8px; margin-bottom: 12px; }
|
||||||
|
.title { font-size: 16px; font-weight: bold; text-transform: uppercase; }
|
||||||
|
.periodo { font-size: 11px; margin-top: 4px; }
|
||||||
|
.section { margin-top: 16px; }
|
||||||
|
.section-title { font-size: 13px; font-weight: bold; border-bottom: 1px solid #000; padding-bottom: 4px; margin-bottom: 8px; }
|
||||||
|
.row { display: flex; justify-content: space-between; padding: 3px 0; }
|
||||||
|
.total { font-weight: bold; margin-top: 8px; border-top: 2px solid #000; padding-top: 8px; }
|
||||||
|
.footer { text-align: center; margin-top: 16px; font-size: 10px; }
|
||||||
|
@media print {
|
||||||
|
@page { size: 80mm auto; margin: 0; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="rel">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">Raul Rock Bar & Café</div>
|
||||||
|
<div class="periodo">Relatório de Pagamentos</div>
|
||||||
|
<div class="periodo">${dataIniStr} - ${dataFimStr}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">RESUMO POR TIPO</div>
|
||||||
|
${Object.entries(porTipo).map(([tipo, valor]) => `
|
||||||
|
<div class="row">
|
||||||
|
<span>${tipo}</span>
|
||||||
|
<span>R$ ${valor.toFixed(2)}</span>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="total">
|
||||||
|
<div class="row">
|
||||||
|
<span>TOTAL GERAL:</span>
|
||||||
|
<span>R$ ${totalGeral.toFixed(2)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<div>------------------------</div>
|
||||||
|
<div>${filtered.length} pagamento(s)</div>
|
||||||
|
<div>Gerado em: ${new Date().toLocaleString('pt-BR')}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
window.electronAPI.printDirect(htmlRelatorio).then(r => {
|
||||||
|
if (r.ok) {
|
||||||
|
showToast('Relatório enviado para impressão!', 'success');
|
||||||
|
} else if (r.error === 'NO_PRINTER') {
|
||||||
|
showToast('Nenhuma impressora configurada.', 'warning', 5000);
|
||||||
|
const printWindow = window.open('', '', 'width=300,height=400');
|
||||||
|
printWindow.document.write(htmlRelatorio);
|
||||||
|
printWindow.document.close();
|
||||||
|
setTimeout(() => printWindow.print(), 300);
|
||||||
|
} else {
|
||||||
|
const printWindow = window.open('', '', 'width=300,height=400');
|
||||||
|
printWindow.document.write(htmlRelatorio);
|
||||||
|
printWindow.document.close();
|
||||||
|
setTimeout(() => printWindow.print(), 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function abrirModalPagamento(tiposPag, comandas) {
|
function abrirModalPagamento(tiposPag, comandas) {
|
||||||
const comandasAbertas = comandas.filter(c => c.status === 'OPEN' || c.status === 'PAYING');
|
const comandasAbertas = comandas.filter(c => c.status === 'OPEN' || c.status === 'PAYING');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user