refactor: migração finaça para API local Postgres e fim do Supabase Sync

This commit is contained in:
Sidney 2026-04-21 21:07:01 -03:00
parent 586f835ae7
commit d537d31187
3 changed files with 55 additions and 37 deletions

View File

@ -355,6 +355,7 @@ const AttendanceQuery: React.FC<AttendanceQueryProps> = ({ data, updateData, dee
);
}
return classStudents.map(student => {
const studentActualRecords = (data.attendance || []).filter(a => a.studentId === student.id && a.classId === selectedClass.id);
const classLessonsRaw = (data.lessons || []).filter(l => l.classId === selectedClass.id && l.status !== 'cancelled');

View File

@ -178,21 +178,19 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
}, [data.payments]);
const syncAsaasPayments = async () => {
if (!isSupabaseConfigured() || isSyncing) return;
if (isSyncing) return;
setIsSyncing(true);
try {
const { data: cloudPayments, error } = await supabase
.from('alunos_cobrancas')
.select('asaas_payment_id, status, aluno_id, valor, vencimento, data_pagamento, installment, asaas_installment_id, link_boleto');
if (error) throw error;
const resp = await fetch('/api/admin/cobrancas');
if (!resp.ok) throw new Error('API fetch failed');
const cloudPayments = await resp.json();
if (cloudPayments && cloudPayments.length > 0) {
let updatedCount = 0;
const currentPayments = dataPaymentsRef.current;
const updatedPayments = currentPayments.map(p => {
const match = cloudPayments.find(cp => {
const match = cloudPayments.find((cp: any) => {
if (p.asaasPaymentId) {
return cp.asaas_payment_id === p.asaasPaymentId;
}
@ -226,7 +224,6 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
if (updatedCount > 0) {
updateData({ payments: updatedPayments });
// Check if any was updated to overdue
const hasOverdue = updatedPayments.some((p, idx) => {
const oldP = currentPayments[idx];
return oldP && oldP.status !== 'overdue' && p.status === 'overdue';
@ -243,33 +240,27 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
if (hasPaid && hasOverdue) message = 'Pagamentos e atrasos atualizados.';
showAlert('Sincronização', message, 'success');
} else {
showAlert('Sincronização', 'Nenhum novo pagamento confirmado encontrado.', 'info');
}
}
} catch (error) {
console.error('Erro ao sincronizar pagamentos:', error);
showAlert('Erro', 'Falha ao sincronizar com o Asaas.', 'error');
// Suppress alert so it doesn't pop up randomly to the user if the server restarts temporarily
} finally {
setIsSyncing(false);
}
};
const fetchSupabaseRecords = async () => {
if (!isSupabaseConfigured()) return;
setIsFetchingSupabase(true);
setSelectedSupabaseRows([]); // Clear selection on refresh
setSelectedSupabaseRows([]);
try {
const { data: records, error } = await supabase
.from('alunos_cobrancas')
.select('*')
.order('vencimento', { ascending: false });
if (error) throw error;
const resp = await fetch('/api/admin/cobrancas');
if (!resp.ok) throw new Error('API fetch failed');
const records = await resp.json();
setSupabaseRecords(records || []);
} catch (error) {
console.error('Error fetching Supabase records:', error);
showAlert('Erro', 'Falha ao buscar dados do Supabase.', 'error');
console.error('Error fetching billing records from Postgres:', error);
showAlert('Erro', 'Falha ao buscar dados do Banco de Dados.', 'error');
} finally {
setIsFetchingSupabase(false);
}
@ -277,34 +268,30 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
const deleteSupabaseRecord = async (id: string) => {
try {
const { error } = await supabase
.from('alunos_cobrancas')
.delete()
.eq('asaas_payment_id', id);
if (error) throw error;
const resp = await fetch(`/api/admin/cobrancas/${id}`, { method: 'DELETE' });
if (!resp.ok) throw new Error('Delete failed');
setSupabaseRecords(prev => prev.filter(r => r.asaas_payment_id !== id));
showAlert('Sucesso', 'Registro removido do Supabase.', 'success');
showAlert('Sucesso', 'Registro removido do Banco.', 'success');
} catch (error) {
console.error('Error deleting Supabase record:', error);
showAlert('Erro', 'Falha ao excluir do Supabase.', 'error');
console.error('Error deleting record:', error);
showAlert('Erro', 'Falha ao excluir do Banco de Dados.', 'error');
}
};
const deleteSupabaseRecordsBulk = async () => {
if (selectedSupabaseRows.length === 0) return;
if(!confirm(`Tem certeza que deseja excluir ${selectedSupabaseRows.length} registros diretamente do Supabase?`)) return;
if(!confirm(`Tem certeza que deseja excluir ${selectedSupabaseRows.length} registros diretamente do Banco de Dados?`)) return;
setIsFetchingSupabase(true);
try {
const { error } = await supabase
.from('alunos_cobrancas')
.delete()
.in('asaas_payment_id', selectedSupabaseRows);
if (error) throw error;
const resp = await fetch('/api/admin/cobrancas', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: selectedSupabaseRows })
});
if (!resp.ok) throw new Error('Bulk delete failed');
setSupabaseRecords(prev => prev.filter(r => !selectedSupabaseRows.includes(r.asaas_payment_id)));
setSelectedSupabaseRows([]);

View File

@ -473,6 +473,36 @@ app.post('/api/webhook_asaas', async (req, res) => {
}
});
// Admin Raw Cobrancas para a Aba Financeiro
app.get('/api/admin/cobrancas', async (req, res) => {
try {
const result = await pool.query('SELECT * FROM alunos_cobrancas ORDER BY vencimento DESC');
res.json(result.rows);
} catch(e) {
res.status(500).json({error: e.message});
}
});
app.delete('/api/admin/cobrancas', async (req, res) => {
try {
const { ids } = req.body;
if (!Array.isArray(ids)) return res.status(400).end();
await pool.query('DELETE FROM alunos_cobrancas WHERE asaas_payment_id = ANY($1)', [ids]);
res.json({ success: true });
} catch(e) {
res.status(500).json({error: e.message});
}
});
app.delete('/api/admin/cobrancas/:id', async (req, res) => {
try {
await pool.query('DELETE FROM alunos_cobrancas WHERE asaas_payment_id = $1', [req.params.id]);
res.json({ success: true });
} catch(e) {
res.status(500).json({error: e.message});
}
});
// Webhook Evolution
app.post('/api/webhooks/evolution', (req, res) => {
try {