fix: restauração da sincronização SQL -> JSON para estabilidade financeira
This commit is contained in:
parent
790c6d055f
commit
abe767a7a6
|
|
@ -183,6 +183,15 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
|
|||
|
||||
setIsSyncing(true);
|
||||
try {
|
||||
// 1. Solicita ao backend que sincronize o SQL para o JSON
|
||||
const syncResp = await fetch('/api/admin/sync-finance-json', { method: 'POST' });
|
||||
const syncResult = await syncResp.json();
|
||||
|
||||
if (syncResult.success && syncResult.updatedCount > 0) {
|
||||
showAlert('Sincronização', `${syncResult.updatedCount} pagamentos foram atualizados e salvos no sistema.`, 'success');
|
||||
}
|
||||
|
||||
// 2. Busca os dados atualizados para exibir na tela
|
||||
const resp = await fetch('/api/admin/cobrancas');
|
||||
if (!resp.ok) throw new Error('API fetch failed');
|
||||
const cloudPayments = await resp.json();
|
||||
|
|
@ -191,14 +200,7 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
|
|||
let updatedCount = 0;
|
||||
const currentPayments = dataPaymentsRef.current;
|
||||
const updatedPayments = currentPayments.map(p => {
|
||||
const match = cloudPayments.find((cp: any) => {
|
||||
if (p.asaasPaymentId) {
|
||||
return cp.asaas_payment_id === p.asaasPaymentId;
|
||||
}
|
||||
return cp.aluno_id === p.studentId &&
|
||||
Math.abs(cp.valor - p.amount) < 0.01 &&
|
||||
cp.vencimento === p.dueDate;
|
||||
});
|
||||
const match = cloudPayments.find((cp: any) => cp.asaas_payment_id === p.asaasPaymentId);
|
||||
|
||||
if (match) {
|
||||
const statusStr = (match.status || '').toLowerCase();
|
||||
|
|
@ -206,14 +208,13 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
|
|||
statusStr === 'atrasado' ? 'overdue' :
|
||||
statusStr === 'cancelado' ? 'cancelled' : 'pending';
|
||||
|
||||
if (p.status !== newStatus || p.amount !== match.valor || p.installmentId !== (match.asaas_installment_id || match.installment) || p.asaasPaymentUrl !== match.link_boleto || p.asaasPaymentId !== match.asaas_payment_id) {
|
||||
if (p.status !== newStatus) {
|
||||
updatedCount++;
|
||||
return {
|
||||
...p,
|
||||
status: newStatus as any,
|
||||
amount: match.valor,
|
||||
amount: Number(match.valor),
|
||||
paidDate: match.data_pagamento || p.paidDate,
|
||||
installmentId: match.asaas_installment_id || match.installment || p.installmentId,
|
||||
asaasPaymentUrl: match.link_boleto || p.asaasPaymentUrl,
|
||||
asaasPaymentId: match.asaas_payment_id || p.asaasPaymentId
|
||||
};
|
||||
|
|
@ -224,28 +225,10 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
|
|||
|
||||
if (updatedCount > 0) {
|
||||
updateData({ payments: updatedPayments });
|
||||
|
||||
const hasOverdue = updatedPayments.some((p, idx) => {
|
||||
const oldP = currentPayments[idx];
|
||||
return oldP && oldP.status !== 'overdue' && p.status === 'overdue';
|
||||
});
|
||||
|
||||
const hasPaid = updatedPayments.some((p, idx) => {
|
||||
const oldP = currentPayments[idx];
|
||||
return oldP && oldP.status !== 'paid' && p.status === 'paid';
|
||||
});
|
||||
|
||||
let message = `${updatedCount} pagamento(s) atualizado(s).`;
|
||||
if (hasPaid && !hasOverdue) message = 'Pagamento confirmado e registrado.';
|
||||
if (hasOverdue && !hasPaid) message = 'Status atualizado para Atrasado.';
|
||||
if (hasPaid && hasOverdue) message = 'Pagamentos e atrasos atualizados.';
|
||||
|
||||
showAlert('Sincronização', message, 'success');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro ao sincronizar pagamentos:', error);
|
||||
// Suppress alert so it doesn't pop up randomly to the user if the server restarts temporarily
|
||||
} finally {
|
||||
setIsSyncing(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1324,6 +1324,43 @@ function agendarRotina(tipo, hora, minuto) {
|
|||
console.log(`[Cron:${label}] ✅ Rotina agendada para ${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')} (America/Sao_Paulo)`);
|
||||
}
|
||||
|
||||
async function syncRelationalToJsonPayments() {
|
||||
try {
|
||||
const { rows: cloudPayments } = await pool.query('SELECT * FROM alunos_cobrancas');
|
||||
const appData = await getSchoolData();
|
||||
let updatedCount = 0;
|
||||
|
||||
if (!appData || !appData.payments) return;
|
||||
|
||||
const updatedPayments = appData.payments.map(p => {
|
||||
const match = cloudPayments.find(cp => cp.asaas_payment_id === p.asaasPaymentId);
|
||||
if (match) {
|
||||
const statusStr = (match.status || '').toLowerCase();
|
||||
const newStatus = statusStr === 'pago' ? 'paid' :
|
||||
statusStr === 'atrasado' ? 'overdue' :
|
||||
statusStr === 'cancelado' ? 'cancelled' : 'pending';
|
||||
|
||||
if (p.status !== newStatus) {
|
||||
updatedCount++;
|
||||
return { ...p, status: newStatus, paidDate: match.data_pagamento || p.paidDate };
|
||||
}
|
||||
}
|
||||
return p;
|
||||
});
|
||||
|
||||
if (updatedCount > 0) {
|
||||
appData.payments = updatedPayments;
|
||||
appData.lastUpdated = new Date().toISOString();
|
||||
await saveSchoolData(appData);
|
||||
console.log(`[Sync:SQL->JSON] ✅ ${updatedCount} status de pagamentos sincronizados com sucesso.`);
|
||||
}
|
||||
return updatedCount;
|
||||
} catch (err) {
|
||||
console.error('[Sync:SQL->JSON] ❌ Erro na sincronização reversa:', err.message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function inicializarAgendamento() {
|
||||
try {
|
||||
// Inicialização DB para colunas de automação (garantir no boot)
|
||||
|
|
@ -1351,6 +1388,9 @@ async function inicializarAgendamento() {
|
|||
// Sincronização de Integridade (JSON -> Tabelas Relacionais)
|
||||
await syncJsonToRelationalTables();
|
||||
|
||||
// Sincronização Reversa (SQL -> JSON) - Garante que status pagos no DB reflitam no painel administrativo
|
||||
await syncRelationalToJsonPayments();
|
||||
|
||||
const appData = await getSchoolData();
|
||||
|
||||
// Migração: Se existirem notas no JSON, movemos para a tabela e removemos do JSON
|
||||
|
|
@ -1426,6 +1466,16 @@ async function startServer() {
|
|||
}
|
||||
});
|
||||
|
||||
// Endpoint para forçar sincronização SQL -> JSON (Aba Financeiro)
|
||||
app.post('/api/admin/sync-finance-json', async (req, res) => {
|
||||
try {
|
||||
const updatedCount = await syncRelationalToJsonPayments();
|
||||
res.json({ success: true, updatedCount });
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: e.message });
|
||||
}
|
||||
});
|
||||
|
||||
// API para gerenciar o agendamento (suporte a preventivo e atrasado)
|
||||
app.get('/api/cron/status', (req, res) => {
|
||||
res.json({
|
||||
|
|
|
|||
Loading…
Reference in New Issue