fix: sincronização financeira JSON-First para restaurar paridade com Asaas
This commit is contained in:
parent
ae971bb2dc
commit
41c32d53d2
|
|
@ -193,11 +193,40 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
|
||||||
console.log('[Sync] Tudo atualizado com o Asaas.');
|
console.log('[Sync] Tudo atualizado com o Asaas.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Busca os dados atualizados para exibir na tela
|
// 2. Busca os dados atualizados do SQL para refletir na UI
|
||||||
const resp = await fetch('/api/admin/cobrancas');
|
const resp = await fetch('/api/admin/cobrancas');
|
||||||
if (!resp.ok) throw new Error('API fetch failed');
|
if (!resp.ok) throw new Error('API fetch failed');
|
||||||
const cloudPayments = await resp.json();
|
const cloudPayments = await resp.json();
|
||||||
|
|
||||||
|
// 3. ATUALIZAÇÃO CRÍTICA: Mescla os dados do SQL com o estado local do React
|
||||||
|
if (Array.isArray(cloudPayments) && cloudPayments.length > 0) {
|
||||||
|
setData(prev => {
|
||||||
|
const newPayments = [...prev.payments];
|
||||||
|
let updated = false;
|
||||||
|
|
||||||
|
cloudPayments.forEach((cp: any) => {
|
||||||
|
const idx = newPayments.findIndex(p => p.asaasPaymentId === cp.asaas_payment_id);
|
||||||
|
if (idx !== -1) {
|
||||||
|
const statusStr = (cp.status || '').toLowerCase();
|
||||||
|
const newStatus = statusStr === 'pago' ? 'paid' :
|
||||||
|
statusStr === 'atrasado' ? 'overdue' :
|
||||||
|
statusStr === 'cancelado' ? 'cancelled' : 'pending';
|
||||||
|
|
||||||
|
if (newPayments[idx].status !== newStatus) {
|
||||||
|
newPayments[idx] = {
|
||||||
|
...newPayments[idx],
|
||||||
|
status: newStatus as any,
|
||||||
|
paidDate: cp.data_pagamento || newPayments[idx].paidDate
|
||||||
|
};
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return updated ? { ...prev, payments: newPayments } : prev;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (cloudPayments && cloudPayments.length > 0) {
|
if (cloudPayments && cloudPayments.length > 0) {
|
||||||
let updatedCount = 0;
|
let updatedCount = 0;
|
||||||
const currentPayments = dataPaymentsRef.current;
|
const currentPayments = dataPaymentsRef.current;
|
||||||
|
|
|
||||||
|
|
@ -1326,24 +1326,25 @@ function agendarRotina(tipo, hora, minuto) {
|
||||||
|
|
||||||
async function syncPaymentsWithAsaasAPI() {
|
async function syncPaymentsWithAsaasAPI() {
|
||||||
try {
|
try {
|
||||||
// Busca abrangente: todos os pagos/confirmados desde o início de 2026
|
console.log(`[Asaas:Sync] 🚀 Iniciando Sincronização JSON-First...`);
|
||||||
|
|
||||||
|
// 1. Carregamos o JSON principal (Fonte de Verdade da UI)
|
||||||
|
const appData = await getSchoolData();
|
||||||
|
if (!appData || !appData.payments) {
|
||||||
|
throw new Error('Dados da escola ou pagamentos não encontrados no JSON.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Definimos as URLs de busca (Pagos e Confirmados)
|
||||||
const url = `${ASAAS_BASE_URL}/v3/payments?limit=100&status=RECEIVED&paymentDate%5Bge%5D=2026-01-01`;
|
const url = `${ASAAS_BASE_URL}/v3/payments?limit=100&status=RECEIVED&paymentDate%5Bge%5D=2026-01-01`;
|
||||||
const urlConfirmed = `${ASAAS_BASE_URL}/v3/payments?limit=100&status=CONFIRMED`;
|
const urlConfirmed = `${ASAAS_BASE_URL}/v3/payments?limit=100&status=CONFIRMED`;
|
||||||
|
|
||||||
console.log(`[Asaas:Sync] 🚀 Iniciando Sincronização Atômica Retroativa...`);
|
|
||||||
|
|
||||||
const fetchPayments = async (targetUrl) => {
|
const fetchPayments = async (targetUrl) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(targetUrl, { headers: { 'access_token': ASAAS_KEY } });
|
const response = await fetch(targetUrl, { headers: { 'access_token': ASAAS_KEY } });
|
||||||
if (!response.ok) {
|
if (!response.ok) return [];
|
||||||
console.error(`[Asaas:Sync] Erro na URL ${targetUrl}: ${response.status}`);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data.data || [];
|
return data.data || [];
|
||||||
} catch (e) {
|
} catch (e) { return []; }
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const received = await fetchPayments(url);
|
const received = await fetchPayments(url);
|
||||||
|
|
@ -1351,8 +1352,8 @@ async function syncPaymentsWithAsaasAPI() {
|
||||||
const allRecent = [...received, ...confirmed];
|
const allRecent = [...received, ...confirmed];
|
||||||
|
|
||||||
if (allRecent.length === 0) {
|
if (allRecent.length === 0) {
|
||||||
console.log('[Asaas:Sync] ℹ Nenhum pagamento confirmado encontrado no Asaas para 2026.');
|
console.log('[Asaas:Sync] ℹ Nenhum pagamento confirmado encontrado no Asaas.');
|
||||||
return await syncRelationalToJsonPayments();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
|
|
@ -1365,37 +1366,51 @@ async function syncPaymentsWithAsaasAPI() {
|
||||||
'DELETED': 'CANCELADO'
|
'DELETED': 'CANCELADO'
|
||||||
};
|
};
|
||||||
|
|
||||||
let totalUpdated = 0;
|
// Mapeamento para o JSON legado
|
||||||
for (const payment of allRecent) {
|
const jsonStatusMap = {
|
||||||
const updateData = {
|
'PAGO': 'paid',
|
||||||
valor: payment.value,
|
'ATRASADO': 'overdue',
|
||||||
vencimento: payment.dueDate,
|
'CANCELADO': 'cancelled',
|
||||||
status: statusMap[payment.status] || 'PENDENTE',
|
'PENDENTE': 'pending'
|
||||||
data_pagamento: payment.confirmedDate || payment.paymentDate || null,
|
|
||||||
link_boleto: payment.bankSlipUrl || payment.invoiceUrl || null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const valorNum = Number(updateData.valor);
|
let totalUpdated = 0;
|
||||||
|
|
||||||
const result = await pool.query(`
|
for (const payment of allRecent) {
|
||||||
|
const internalStatus = statusMap[payment.status] || 'PENDENTE';
|
||||||
|
const valorNum = Number(payment.value);
|
||||||
|
|
||||||
|
// A. Atualiza o SQL (Backup e Relatórios)
|
||||||
|
await pool.query(`
|
||||||
INSERT INTO alunos_cobrancas (asaas_payment_id, valor, vencimento, status, data_pagamento, link_boleto)
|
INSERT INTO alunos_cobrancas (asaas_payment_id, valor, vencimento, status, data_pagamento, link_boleto)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6)
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
ON CONFLICT (asaas_payment_id) DO UPDATE SET
|
ON CONFLICT (asaas_payment_id) DO UPDATE SET
|
||||||
valor = EXCLUDED.valor,
|
|
||||||
vencimento = EXCLUDED.vencimento,
|
|
||||||
status = EXCLUDED.status,
|
status = EXCLUDED.status,
|
||||||
data_pagamento = EXCLUDED.data_pagamento,
|
data_pagamento = EXCLUDED.data_pagamento
|
||||||
link_boleto = EXCLUDED.link_boleto
|
`, [payment.id, valorNum, payment.dueDate, internalStatus, payment.confirmedDate || payment.paymentDate, payment.bankSlipUrl || payment.invoiceUrl]);
|
||||||
RETURNING *
|
|
||||||
`, [payment.id, valorNum, updateData.vencimento, updateData.status, updateData.data_pagamento, updateData.link_boleto]);
|
|
||||||
|
|
||||||
if (result.rowCount > 0) totalUpdated++;
|
// B. Atualiza o JSON (Visualização na Tela)
|
||||||
|
const pIdx = appData.payments.findIndex(p => p.asaasPaymentId === payment.id);
|
||||||
|
if (pIdx !== -1) {
|
||||||
|
const newJsonStatus = jsonStatusMap[internalStatus] || 'pending';
|
||||||
|
if (appData.payments[pIdx].status !== newJsonStatus) {
|
||||||
|
appData.payments[pIdx].status = newJsonStatus;
|
||||||
|
appData.payments[pIdx].paidDate = payment.confirmedDate || payment.paymentDate || appData.payments[pIdx].paidDate;
|
||||||
|
totalUpdated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[Asaas:Sync] ✅ Sincronização SQL concluída. Processados ${allRecent.length} itens.`);
|
// 3. Salva o JSON atualizado (Isso reflete na UI imediatamente)
|
||||||
return await syncRelationalToJsonPayments();
|
if (totalUpdated > 0) {
|
||||||
|
appData.lastUpdated = new Date().toISOString();
|
||||||
|
await saveSchoolData(appData);
|
||||||
|
console.log(`[Asaas:Sync] ✅ Sincronização concluída: ${totalUpdated} pagamentos atualizados no JSON.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalUpdated;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Asaas:Sync] ❌ Erro fatal na sincronização:', err.message);
|
console.error('[Asaas:Sync] ❌ Erro na sincronização JSON-First:', err.message);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue