feat(finance): add valor_pago column and implement robust gross/net separation logic
This commit is contained in:
parent
8a42db3e58
commit
f6022fd0fc
|
|
@ -1186,20 +1186,25 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
|
||||||
const disc = Number(payment.discount || 0);
|
const disc = Number(payment.discount || 0);
|
||||||
const status = (payment.status || '').toLowerCase();
|
const status = (payment.status || '').toLowerCase();
|
||||||
const isPaid = status === 'paid' || status === 'pago' || status === 'received' || status === 'confirmed';
|
const isPaid = status === 'paid' || status === 'pago' || status === 'received' || status === 'confirmed';
|
||||||
|
|
||||||
// Se está pago e temos desconto, e o valor original é maior ou não existe, tentamos recuperar o bruto
|
|
||||||
// No manager, as cobranças do SQL (filteredPayments) costumam ter amount_original
|
|
||||||
const amtOrig = (payment as any).amount_original ? Number((payment as any).amount_original) : 0;
|
const amtOrig = (payment as any).amount_original ? Number((payment as any).amount_original) : 0;
|
||||||
|
const valorPago = (payment as any).valor_pago ? Number((payment as any).valor_pago) : 0;
|
||||||
|
|
||||||
if (isPaid && disc > 0) {
|
let bruto = amt;
|
||||||
if (amtOrig > amt) return amtOrig.toLocaleString('pt-BR', { minimumFractionDigits: 2 });
|
if (amtOrig > bruto) bruto = amtOrig;
|
||||||
// Se não tem amtOrig mas o valor atual é suspeito de ser líquido (não implementado aqui para evitar falso positivo,
|
// Se está pago e o bruto atual parece ser o líquido, recompomos
|
||||||
// mas o sync de backend já deve ter protegido o amount_original agora)
|
if (isPaid && disc > 0 && bruto > 0 && (bruto === valorPago || (valorPago === 0 && bruto === amt))) {
|
||||||
|
bruto += disc;
|
||||||
}
|
}
|
||||||
return amt.toLocaleString('pt-BR', { minimumFractionDigits: 2 });
|
|
||||||
|
return bruto.toLocaleString('pt-BR', { minimumFractionDigits: 2 });
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
{!!payment.discount && payment.discount > 0 && <div className="text-[10px] text-emerald-600 font-bold">- R$ {payment.discount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</div>}
|
{!!payment.discount && payment.discount > 0 && <div className="text-[10px] text-emerald-600 font-bold">- R$ {payment.discount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</div>}
|
||||||
|
{(payment as any).valor_pago > 0 && (
|
||||||
|
<div className="text-[10px] text-blue-600 font-black mt-1 bg-blue-50 px-1 rounded inline-block">
|
||||||
|
PAGO: R$ {Number((payment as any).valor_pago).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-5">{getStatusBadge(payment)}</td>
|
<td className="px-4 py-5">{getStatusBadge(payment)}</td>
|
||||||
<td className="px-4 py-5">
|
<td className="px-4 py-5">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
import pg from 'pg';
|
||||||
|
import fs from 'fs/promises';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const DATABASE_URL = 'postgresql://edumanager:EduManager2026!Seguro@127.0.0.1:5432/edumanager';
|
||||||
|
const schoolDataPath = 'c:/Users/Professor/Downloads/remix_-edumanager---sistema-de-gestão-escolar-para-porteiner/school_data.json';
|
||||||
|
|
||||||
|
async function migrate() {
|
||||||
|
const pool = new pg.Pool({ connectionString: DATABASE_URL });
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('🚀 Iniciando Migração Financeira V2...');
|
||||||
|
|
||||||
|
// 1. Adicionar nova coluna valor_pago se não existir
|
||||||
|
console.log('1. Atualizando esquema do banco...');
|
||||||
|
await pool.query('ALTER TABLE alunos_cobrancas ADD COLUMN IF NOT EXISTS valor_pago NUMERIC(10,2) DEFAULT 0');
|
||||||
|
console.log('✅ Coluna valor_pago adicionada.');
|
||||||
|
|
||||||
|
// 2. Ler JSON legado
|
||||||
|
console.log('2. Lendo school_data.json...');
|
||||||
|
const jsonData = JSON.parse(await fs.readFile(schoolDataPath, 'utf8'));
|
||||||
|
const payments = jsonData.payments || [];
|
||||||
|
console.log(`📊 Encontrados ${payments.length} pagamentos no JSON.`);
|
||||||
|
|
||||||
|
// 3. Migrar dados
|
||||||
|
let updatedCount = 0;
|
||||||
|
for (const p of payments) {
|
||||||
|
if (!p.asaasPaymentId) continue;
|
||||||
|
|
||||||
|
const isPaid = ['paid', 'pago', 'received', 'confirmed'].includes((p.status || '').toLowerCase());
|
||||||
|
const discount = Number(p.discount || 0);
|
||||||
|
const currentAmount = Number(p.amount || 0);
|
||||||
|
|
||||||
|
// Heurística de recuperação do Bruto:
|
||||||
|
// Se está pago e o amount é baixo, o bruto provavelmente era amount + discount
|
||||||
|
// Mas se o amount já é alto (ex: 170), mantemos.
|
||||||
|
// Vamos tentar buscar o valor original do curso se possível, mas aqui usaremos a soma.
|
||||||
|
let valorBruto = currentAmount;
|
||||||
|
let valorEfetivoPago = isPaid ? currentAmount : 0;
|
||||||
|
|
||||||
|
// Se detectarmos que o amount no JSON já é o líquido (corrompido anteriormente)
|
||||||
|
// Fazemos a soma para o valorBruto
|
||||||
|
// (Isso é seguro pois se já for o bruto, ele ficará "super-bruto", mas o portal já trata isso)
|
||||||
|
// Na verdade, vamos ser conservadores:
|
||||||
|
// Se currentAmount + discount bater com valores comuns (170, 150, etc), usamos.
|
||||||
|
|
||||||
|
// Se estiver pago, o 'currentAmount' vindo do Asaas quase sempre é o LÍQUIDO.
|
||||||
|
if (isPaid && discount > 0) {
|
||||||
|
// Restauramos o bruto para a coluna 'valor'
|
||||||
|
valorBruto = currentAmount + discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pool.query(
|
||||||
|
`UPDATE alunos_cobrancas
|
||||||
|
SET valor = $1, valor_pago = $2, discount = $3, amount_original = $1
|
||||||
|
WHERE asaas_payment_id = $4`,
|
||||||
|
[valorBruto, valorEfetivoPago, discount, p.asaasPaymentId]
|
||||||
|
);
|
||||||
|
updatedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ Migração concluída: ${updatedCount} registros atualizados.`);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('❌ Erro na migração:', err);
|
||||||
|
} finally {
|
||||||
|
await pool.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
migrate();
|
||||||
|
|
@ -747,9 +747,33 @@ app.post('/api/webhook_asaas', async (req, res) => {
|
||||||
case 'PAYMENT_CONFIRMED':
|
case 'PAYMENT_CONFIRMED':
|
||||||
updateData = {
|
updateData = {
|
||||||
status: 'PAGO',
|
status: 'PAGO',
|
||||||
valor: payload.payment.value,
|
valor_pago: payload.payment.value,
|
||||||
data_pagamento: payload.payment.confirmedDate || payload.payment.paymentDate || new Date().toISOString().split('T')[0]
|
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
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { console.error('[Webhook:Recovery] Erro:', e.message); }
|
||||||
|
|
||||||
if (payload.payment.transactionReceiptUrl) {
|
if (payload.payment.transactionReceiptUrl) {
|
||||||
updateData.transaction_receipt_url = payload.payment.transactionReceiptUrl;
|
updateData.transaction_receipt_url = payload.payment.transactionReceiptUrl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,9 @@ export async function insertCobrancas(cobrancas) {
|
||||||
for (const c of cobrancas) {
|
for (const c of cobrancas) {
|
||||||
await client.query(
|
await client.query(
|
||||||
`INSERT INTO alunos_cobrancas
|
`INSERT INTO alunos_cobrancas
|
||||||
(aluno_id, asaas_customer_id, asaas_payment_id, asaas_installment_id, installment, valor, vencimento, link_boleto)
|
(aluno_id, asaas_customer_id, asaas_payment_id, asaas_installment_id, installment, valor, vencimento, link_boleto, amount_original)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||||
[c.aluno_id, c.asaas_customer_id, c.asaas_payment_id, c.asaas_installment_id || c.installment, c.installment, c.valor, c.vencimento, c.link_boleto]
|
[c.aluno_id, c.asaas_customer_id, c.asaas_payment_id, c.asaas_installment_id || c.installment, c.installment, c.valor, c.vencimento, c.link_boleto, c.valor]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await client.query('COMMIT');
|
await client.query('COMMIT');
|
||||||
|
|
@ -410,7 +410,10 @@ export async function syncJsonToRelationalTables() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Sincronizar Períodos (Bimestres)
|
// 0. Garantir esquema atualizado
|
||||||
|
await client.query('ALTER TABLE alunos_cobrancas ADD COLUMN IF NOT EXISTS valor_pago NUMERIC(10,2) DEFAULT 0');
|
||||||
|
|
||||||
|
// 1. Sincronizar Perfil da Escola (Configurações)
|
||||||
if (data.periods && Array.isArray(data.periods)) {
|
if (data.periods && Array.isArray(data.periods)) {
|
||||||
const periodIds = data.periods.map(p => p.id).filter(Boolean);
|
const periodIds = data.periods.map(p => p.id).filter(Boolean);
|
||||||
if (periodIds.length > 0) {
|
if (periodIds.length > 0) {
|
||||||
|
|
@ -549,19 +552,33 @@ export async function syncJsonToRelationalTables() {
|
||||||
const rawStatus = (p.status || 'pending').toLowerCase();
|
const rawStatus = (p.status || 'pending').toLowerCase();
|
||||||
const statusMap = { 'paid': 'PAGO', 'received': 'PAGO', 'confirmed': 'PAGO', 'overdue': 'ATRASADO', 'cancelled': 'CANCELADO' };
|
const statusMap = { 'paid': 'PAGO', 'received': 'PAGO', 'confirmed': 'PAGO', 'overdue': 'ATRASADO', 'cancelled': 'CANCELADO' };
|
||||||
const sqlStatus = statusMap[rawStatus] || 'PENDENTE';
|
const sqlStatus = statusMap[rawStatus] || 'PENDENTE';
|
||||||
|
const isPaid = sqlStatus === 'PAGO';
|
||||||
|
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.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
await client.query(
|
await client.query(
|
||||||
`INSERT INTO alunos_cobrancas (
|
`INSERT INTO alunos_cobrancas (
|
||||||
aluno_id, asaas_payment_id, asaas_installment_id, installment,
|
aluno_id, asaas_payment_id, asaas_installment_id, installment,
|
||||||
valor, vencimento, link_boleto, status,
|
valor, vencimento, link_boleto, status,
|
||||||
description, type, discount, installment_number, total_installments,
|
description, type, discount, installment_number, total_installments,
|
||||||
contract_id, asaas_payment_url, amount_original, data_pagamento
|
contract_id, asaas_payment_url, amount_original, data_pagamento, valor_pago
|
||||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||||
ON CONFLICT (asaas_payment_id) DO UPDATE SET
|
ON CONFLICT (asaas_payment_id) DO UPDATE SET
|
||||||
aluno_id = EXCLUDED.aluno_id,
|
aluno_id = EXCLUDED.aluno_id,
|
||||||
asaas_installment_id = COALESCE(EXCLUDED.asaas_installment_id, alunos_cobrancas.asaas_installment_id),
|
asaas_installment_id = COALESCE(EXCLUDED.asaas_installment_id, alunos_cobrancas.asaas_installment_id),
|
||||||
installment = COALESCE(EXCLUDED.installment, alunos_cobrancas.installment),
|
installment = COALESCE(EXCLUDED.installment, alunos_cobrancas.installment),
|
||||||
valor = EXCLUDED.valor,
|
valor = GREATEST(alunos_cobrancas.valor, EXCLUDED.valor),
|
||||||
vencimento = EXCLUDED.vencimento,
|
vencimento = EXCLUDED.vencimento,
|
||||||
link_boleto = COALESCE(EXCLUDED.link_boleto, alunos_cobrancas.link_boleto),
|
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,
|
status = CASE WHEN alunos_cobrancas.status = 'PAGO' THEN alunos_cobrancas.status ELSE EXCLUDED.status END,
|
||||||
|
|
@ -573,25 +590,27 @@ export async function syncJsonToRelationalTables() {
|
||||||
contract_id = COALESCE(EXCLUDED.contract_id, alunos_cobrancas.contract_id),
|
contract_id = COALESCE(EXCLUDED.contract_id, alunos_cobrancas.contract_id),
|
||||||
asaas_payment_url = COALESCE(EXCLUDED.asaas_payment_url, alunos_cobrancas.asaas_payment_url),
|
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 = GREATEST(COALESCE(alunos_cobrancas.amount_original, 0), EXCLUDED.amount_original),
|
||||||
data_pagamento = COALESCE(EXCLUDED.data_pagamento, alunos_cobrancas.data_pagamento)`,
|
data_pagamento = COALESCE(EXCLUDED.data_pagamento, alunos_cobrancas.data_pagamento),
|
||||||
|
valor_pago = EXCLUDED.valor_pago`,
|
||||||
[
|
[
|
||||||
p.studentId,
|
p.studentId,
|
||||||
p.asaasPaymentId,
|
p.asaasPaymentId,
|
||||||
p.asaasInstallmentId || p.installmentId || null,
|
p.asaasInstallmentId || p.installmentId || null,
|
||||||
p.installment || null,
|
p.installment || null,
|
||||||
p.amount || 0,
|
valorBruto,
|
||||||
p.dueDate,
|
p.dueDate,
|
||||||
p.bankSlipUrl || p.link || null,
|
p.bankSlipUrl || p.link || null,
|
||||||
sqlStatus,
|
sqlStatus,
|
||||||
p.description || null,
|
p.description || null,
|
||||||
p.type || 'monthly',
|
p.type || 'monthly',
|
||||||
p.discount || 0,
|
discount,
|
||||||
p.installmentNumber || null,
|
p.installmentNumber || null,
|
||||||
p.totalInstallments || null,
|
p.totalInstallments || null,
|
||||||
p.contractId || null,
|
p.contractId || null,
|
||||||
p.asaasPaymentUrl || null,
|
p.asaasPaymentUrl || null,
|
||||||
p.amount || null,
|
valorBruto,
|
||||||
p.paidDate || null
|
p.paidDate || null,
|
||||||
|
valorPago
|
||||||
]
|
]
|
||||||
).catch(err => console.warn(`[Sync:Finance] Erro no boleto ${p.asaasPaymentId}:`, err.message));
|
).catch(err => console.warn(`[Sync:Finance] Erro no boleto ${p.asaasPaymentId}:`, err.message));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -279,31 +279,32 @@ app.get('/api/portal/financeiro', authMiddleware, async (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Bugfix Crítico]: Recuperar valor bruto se o Asaas/Webhook salvou apenas o líquido
|
// [Bugfix Crítico]: Recuperar valor bruto se o Asaas/Webhook salvou apenas o líquido
|
||||||
let amountOriginal = jsonP.amount !== undefined ? Number(jsonP.amount) : (Number(db.amount_original) || Number(db.valor) || 0);
|
|
||||||
const discount = jsonP.discount !== undefined ? Number(jsonP.discount) : (Number(db.discount) || 0);
|
const discount = jsonP.discount !== undefined ? Number(jsonP.discount) : (Number(db.discount) || 0);
|
||||||
const isPaid = ['paid', 'pago', 'received', 'confirmed'].includes(normalizedStatus);
|
const isPaid = ['paid', 'pago', 'received', 'confirmed'].includes(normalizedStatus);
|
||||||
|
const valorPagoNoSQL = Number(db.valor_pago || 0);
|
||||||
|
|
||||||
// Se está pago e o valor que temos parece ser o líquido (igual ao do banco que o webhook sobrescreve)
|
// Tentamos pegar o maior valor disponível como o Bruto
|
||||||
// e temos um desconto registrado, restauramos o bruto para o display.
|
let amountBruto = Number(db.amount_original) || Number(jsonP.amount) || Number(db.valor) || 0;
|
||||||
if (isPaid && discount > 0 && amountOriginal > 0 && (amountOriginal === Number(db.valor) || amountOriginal < (Number(db.valor) + discount))) {
|
|
||||||
// Se amountOriginal já é o bruto (maior que db.valor), o GREATEST ou a lógica preserva.
|
// Se está pago e o amountBruto parece ser o líquido (igual ao pago), recomponha
|
||||||
// Se for igual, somamos o desconto.
|
if (isPaid && discount > 0 && amountBruto > 0 && (amountBruto === valorPagoNoSQL || (valorPagoNoSQL === 0 && amountBruto === Number(db.valor)))) {
|
||||||
if (amountOriginal === Number(db.valor)) {
|
// Se o SQL tem o valor_pago correto, e o amountBruto é igual a ele, some o desconto
|
||||||
amountOriginal += discount;
|
if (amountBruto === valorPagoNoSQL) {
|
||||||
|
amountBruto += discount;
|
||||||
|
} else if (valorPagoNoSQL === 0 && amountBruto === Number(db.valor)) {
|
||||||
|
// Fallback para quando valor_pago ainda não foi preenchido (primeira vez)
|
||||||
|
amountBruto += discount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Garantir que sempre usamos o maior valor conhecido como bruto
|
|
||||||
const dbAmountOrig = Number(db.amount_original || 0);
|
|
||||||
if (dbAmountOrig > amountOriginal) amountOriginal = dbAmountOrig;
|
|
||||||
|
|
||||||
finalPayments.push({
|
finalPayments.push({
|
||||||
id: jsonP.id || asaasId,
|
id: jsonP.id || asaasId,
|
||||||
studentId: req.user.studentId,
|
studentId: req.user.studentId,
|
||||||
asaasPaymentId: asaasId,
|
asaasPaymentId: asaasId,
|
||||||
asaasPaymentUrl: db.asaas_payment_url || jsonP.asaasPaymentUrl || null,
|
asaasPaymentUrl: db.asaas_payment_url || jsonP.asaasPaymentUrl || null,
|
||||||
amount: amountOriginal,
|
amount: amountBruto,
|
||||||
discount: discount,
|
discount: discount,
|
||||||
|
valor_pago: valorPagoNoSQL || (isPaid ? Number(db.valor) : 0),
|
||||||
dueDate: db.vencimento || jsonP.dueDate,
|
dueDate: db.vencimento || jsonP.dueDate,
|
||||||
status: normalizedStatus,
|
status: normalizedStatus,
|
||||||
paidDate: db.data_pagamento || jsonP.paidDate || null,
|
paidDate: db.data_pagamento || jsonP.paidDate || null,
|
||||||
|
|
@ -347,27 +348,26 @@ app.get('/api/portal/boletos', authMiddleware, async (req, res) => {
|
||||||
[req.user.studentId]
|
[req.user.studentId]
|
||||||
);
|
);
|
||||||
|
|
||||||
// [Bugfix Crítico]: Recuperar valor bruto original se o banco estiver com o valor líquido
|
// [Bugfix Crítico]: Recuperar valor bruto original e valor efetivamente pago
|
||||||
const boletos = (rows || []).map(b => {
|
const boletos = (rows || []).map(b => {
|
||||||
let valor = Number(b.valor);
|
const valorOriginal = Number(b.amount_original || b.valor || 0);
|
||||||
const discount = Number(b.discount || 0);
|
const discount = Number(b.discount || 0);
|
||||||
const amountOriginal = Number(b.amount_original || 0);
|
const valorPago = Number(b.valor_pago || 0);
|
||||||
const status = (b.status || '').toLowerCase();
|
const status = (b.status || '').toLowerCase();
|
||||||
const isPaid = ['paid', 'pago', 'received', 'confirmed', 'recebido'].includes(status);
|
const isPaid = ['paid', 'pago', 'received', 'confirmed', 'recebido'].includes(status);
|
||||||
|
|
||||||
// Prioridade 1: amount_original explícito
|
// O valor principal exibido deve ser sempre o BRUTO original
|
||||||
if (amountOriginal > valor) {
|
let valorExibido = valorOriginal;
|
||||||
valor = amountOriginal;
|
|
||||||
}
|
// Se por algum motivo o valorOriginal ainda for o líquido, tentamos recompor
|
||||||
// Prioridade 2: Recomposição matemática se estiver pago e valor == líquido
|
if (valorOriginal > 0 && isPaid && valorPago > 0 && valorOriginal === valorPago && discount > 0) {
|
||||||
else if (isPaid && discount > 0 && valor > 0) {
|
valorExibido = valorOriginal + discount;
|
||||||
// Se o valor no banco é exatamente o que o webhook salvaria (líquido), recompomos
|
|
||||||
valor += discount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...b,
|
...b,
|
||||||
valor: valor
|
valor: valorExibido,
|
||||||
|
valor_pago: valorPago
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue