fix(sync): correct financial sync logic to prevent inflating installment values with discount
This commit is contained in:
parent
054bd5ef7b
commit
a9f8559462
|
|
@ -0,0 +1,26 @@
|
|||
const pg = require('pg');
|
||||
const pool = new pg.Pool({ connectionString: 'postgresql://edumanager:EduManager2026!Seguro@150.230.87.131:5432/edumanager' });
|
||||
|
||||
async function fix() {
|
||||
// 1. Corrigir parcelas PAGAS: valor=170, amount_original=170, valor_pago=150
|
||||
const r1 = await pool.query(
|
||||
"UPDATE alunos_cobrancas SET valor = 170, amount_original = 170, valor_pago = 150 WHERE status = 'PAGO' AND discount = 20"
|
||||
);
|
||||
console.log('Parcelas PAGAS corrigidas:', r1.rowCount);
|
||||
|
||||
// 2. Corrigir parcelas PENDENTES que tenham valor inflado
|
||||
const r2 = await pool.query(
|
||||
"UPDATE alunos_cobrancas SET amount_original = valor WHERE amount_original != valor AND discount = 20"
|
||||
);
|
||||
console.log('Amount_original alinhado:', r2.rowCount);
|
||||
|
||||
// 3. Verificar resultado
|
||||
const { rows } = await pool.query(
|
||||
"SELECT status, count(*), sum(valor) as total_valor, sum(valor_pago) as total_pago, sum(discount) as total_desconto FROM alunos_cobrancas GROUP BY status"
|
||||
);
|
||||
console.table(rows);
|
||||
|
||||
await pool.end();
|
||||
}
|
||||
|
||||
fix().catch(e => { console.error(e); pool.end(); });
|
||||
|
|
@ -752,25 +752,19 @@ app.post('/api/webhook_asaas', async (req, res) => {
|
|||
data_pagamento: payload.payment.confirmedDate || payload.payment.paymentDate || new Date().toISOString().split('T')[0]
|
||||
};
|
||||
|
||||
// [Bugfix Crítico]: Recuperar o valor BRUTO caso o Asaas mande o líquido
|
||||
// Preservar o valor original da parcela — não inflar com desconto
|
||||
try {
|
||||
const cobRes = await pool.query('SELECT valor, discount, amount_original FROM alunos_cobrancas WHERE asaas_payment_id = $1', [asaasPaymentId]);
|
||||
if (cobRes.rows.length > 0) {
|
||||
const cob = cobRes.rows[0];
|
||||
const currentAmount = Number(cob.valor || 0);
|
||||
const storedValor = Number(cob.valor || 0);
|
||||
const discount = Number(cob.discount || 0);
|
||||
const amountOriginal = Number(cob.amount_original || 0);
|
||||
const receivedValue = Number(payload.payment.value);
|
||||
|
||||
// Se o valor recebido for menor que o bruto registrado e a diferença bater com o desconto,
|
||||
// mantemos o bruto no campo 'valor'.
|
||||
if (receivedValue < currentAmount && Math.abs((currentAmount - discount) - receivedValue) < 0.01) {
|
||||
// Já está correto (bruto > recebido), não mexemos no 'valor'
|
||||
} else if (receivedValue === currentAmount && discount > 0) {
|
||||
// Se o 'valor' no banco já era o líquido, restauramos para o bruto
|
||||
updateData.valor = receivedValue + discount;
|
||||
} else if (amountOriginal > receivedValue) {
|
||||
updateData.valor = amountOriginal;
|
||||
// Se o Asaas enviou o valor líquido (menor que o registrado),
|
||||
// registramos como valor_pago e preservamos o valor da parcela
|
||||
if (receivedValue < storedValor) {
|
||||
updateData.valor_pago = receivedValue;
|
||||
}
|
||||
}
|
||||
} catch (e) { console.error('[Webhook:Recovery] Erro:', e.message); }
|
||||
|
|
@ -1739,8 +1733,8 @@ async function syncPaymentsWithAsaasAPI() {
|
|||
ON CONFLICT (asaas_payment_id) DO UPDATE SET
|
||||
status = EXCLUDED.status,
|
||||
data_pagamento = EXCLUDED.data_pagamento,
|
||||
valor_pago = GREATEST(alunos_cobrancas.valor_pago, EXCLUDED.valor_pago),
|
||||
valor = GREATEST(alunos_cobrancas.valor, EXCLUDED.valor)
|
||||
valor_pago = CASE WHEN EXCLUDED.valor_pago > 0 THEN EXCLUDED.valor_pago ELSE alunos_cobrancas.valor_pago END,
|
||||
valor = COALESCE(NULLIF(EXCLUDED.valor, 0), alunos_cobrancas.valor)
|
||||
`, [payment.id, valorNum, payment.dueDate, internalStatus, payment.confirmedDate || payment.paymentDate, receivedValue]).catch(() => {});
|
||||
|
||||
// B. Atualiza JSON
|
||||
|
|
@ -1812,7 +1806,7 @@ async function syncRelationalToJsonPayments() {
|
|||
|
||||
const hasChanges = p.status !== newStatus ||
|
||||
Number(p.valor_pago || 0) !== Number(match.valor_pago || 0) ||
|
||||
Number(p.amount || 0) !== Math.max(Number(match.amount_original || 0), Number(match.valor || 0));
|
||||
Number(p.amount || 0) !== Number(match.valor || 0);
|
||||
|
||||
if (hasChanges) {
|
||||
updatedCount++;
|
||||
|
|
@ -1821,7 +1815,7 @@ async function syncRelationalToJsonPayments() {
|
|||
status: newStatus,
|
||||
paidDate: match.data_pagamento || p.paidDate,
|
||||
valor_pago: Number(match.valor_pago || 0),
|
||||
amount: Math.max(Number(match.amount_original || 0), Number(match.valor || 0))
|
||||
amount: Number(match.valor || p.amount || 0)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -556,15 +556,14 @@ export async function syncJsonToRelationalTables() {
|
|||
const amount = Number(p.amount || 0);
|
||||
const discount = Number(p.discount || 0);
|
||||
|
||||
// Se está pago, o 'amount' do JSON geralmente é o líquido.
|
||||
// O valor principal (valor) deve ser o BRUTO.
|
||||
// O valor da parcela (face value) é sempre o amount do JSON (ex: 170)
|
||||
// O desconto é condicional e NÃO altera o valor base da parcela
|
||||
let valorBruto = amount;
|
||||
let valorPago = 0;
|
||||
|
||||
if (isPaid) {
|
||||
valorPago = amount;
|
||||
// Se o amount vindo do JSON for o líquido (igual ou menor que o bruto esperado), restauramos o bruto
|
||||
valorBruto = amount + discount;
|
||||
// Usar valor_pago explícito do JSON se disponível, senão calcular (amount - discount)
|
||||
valorPago = Number(p.valor_pago || 0) || (amount - discount);
|
||||
}
|
||||
|
||||
await client.query(
|
||||
|
|
@ -578,7 +577,7 @@ export async function syncJsonToRelationalTables() {
|
|||
aluno_id = EXCLUDED.aluno_id,
|
||||
asaas_installment_id = COALESCE(EXCLUDED.asaas_installment_id, alunos_cobrancas.asaas_installment_id),
|
||||
installment = COALESCE(EXCLUDED.installment, alunos_cobrancas.installment),
|
||||
valor = GREATEST(alunos_cobrancas.valor, EXCLUDED.valor),
|
||||
valor = EXCLUDED.valor,
|
||||
vencimento = EXCLUDED.vencimento,
|
||||
link_boleto = COALESCE(EXCLUDED.link_boleto, alunos_cobrancas.link_boleto),
|
||||
status = CASE WHEN alunos_cobrancas.status = 'PAGO' THEN alunos_cobrancas.status ELSE EXCLUDED.status END,
|
||||
|
|
@ -589,7 +588,7 @@ export async function syncJsonToRelationalTables() {
|
|||
total_installments = COALESCE(EXCLUDED.total_installments, alunos_cobrancas.total_installments),
|
||||
contract_id = COALESCE(EXCLUDED.contract_id, alunos_cobrancas.contract_id),
|
||||
asaas_payment_url = COALESCE(EXCLUDED.asaas_payment_url, alunos_cobrancas.asaas_payment_url),
|
||||
amount_original = GREATEST(COALESCE(alunos_cobrancas.amount_original, 0), EXCLUDED.amount_original),
|
||||
amount_original = COALESCE(EXCLUDED.amount_original, alunos_cobrancas.amount_original),
|
||||
data_pagamento = COALESCE(EXCLUDED.data_pagamento, alunos_cobrancas.data_pagamento),
|
||||
valor_pago = EXCLUDED.valor_pago`,
|
||||
[
|
||||
|
|
|
|||
Loading…
Reference in New Issue