diff --git a/manager/server.selfhosted.js b/manager/server.selfhosted.js index ad66550..19fdd1a 100644 --- a/manager/server.selfhosted.js +++ b/manager/server.selfhosted.js @@ -645,12 +645,12 @@ async function sendEvolutionMessage(asaasPaymentId, eventType, fallbackValorArg const pdfArrayBuffer = doc.output('arraybuffer'); const pdfBuffer = Buffer.from(pdfArrayBuffer); - // Upload para o MinIO (Pasta recibos) + // Upload para o MinIO (Pasta recibos) — apenas para envio via WhatsApp const minioFileName = `recibos/recibo_${asaasPaymentId}.pdf`; const minioUrl = await uploadReceiptToStorage(minioFileName, pdfBuffer); - // Atualiza o link no banco de dados para apontar para o seu MinIO - await updateCobranca(asaasPaymentId, { transaction_receipt_url: minioUrl }); + // NÃO sobrescrever transaction_receipt_url — o link do Asaas (público) é salvo pelo webhook + // O MinIO é usado apenas para o envio do PDF via WhatsApp base64Pdf = pdfBuffer.toString('base64'); fileName = `Recibo-${targetName.replace(/\s+/g, '')}.pdf`; diff --git a/portal/server.js b/portal/server.js index 667bac5..0a54f06 100644 --- a/portal/server.js +++ b/portal/server.js @@ -281,8 +281,8 @@ app.get('/api/portal/financeiro', authMiddleware, async (req, res) => { studentId: req.user.studentId, asaasPaymentId: asaasId, asaasPaymentUrl: jsonP.asaasPaymentUrl || null, - amount: Number(db.valor) || jsonP.amount || 0, - discount: jsonP.discount || 0, + amount: jsonP.amount || Number(db.valor) || 0, + discount: jsonP.amount ? (jsonP.discount || 0) : 0, dueDate: db.vencimento || jsonP.dueDate, status: normalizedStatus, paidDate: db.data_pagamento || jsonP.paidDate || null, diff --git a/portal/server.selfhosted.js b/portal/server.selfhosted.js index 2f6fa1b..11ec6f8 100644 --- a/portal/server.selfhosted.js +++ b/portal/server.selfhosted.js @@ -285,8 +285,10 @@ app.get('/api/portal/financeiro', authMiddleware, async (req, res) => { studentId: req.user.studentId, asaasPaymentId: asaasId, asaasPaymentUrl: jsonP.asaasPaymentUrl || null, - amount: Number(db.valor) || jsonP.amount || 0, - discount: jsonP.discount || 0, + // jsonP.amount = valor BRUTO (ex: 170), db.valor = valor LÍQUIDO do Asaas (ex: 150) + // Se o JSON tem o bruto, usa ele + desconto separado. Se não, usa SQL (já líquido) sem desconto. + amount: jsonP.amount || Number(db.valor) || 0, + discount: jsonP.amount ? (jsonP.discount || 0) : 0, dueDate: db.vencimento || jsonP.dueDate, status: normalizedStatus, paidDate: db.data_pagamento || jsonP.paidDate || null, diff --git a/portal/src/pages/Financeiro.tsx b/portal/src/pages/Financeiro.tsx index 663fa2e..435df72 100644 --- a/portal/src/pages/Financeiro.tsx +++ b/portal/src/pages/Financeiro.tsx @@ -96,9 +96,11 @@ export default function Financeiro() { }; const getReceiptLink = (payment: Payment): string | null => { - if ((payment as any).transactionReceiptUrl) return (payment as any).transactionReceiptUrl; - if ((payment as any).transaction_receipt_url) return (payment as any).transaction_receipt_url; + // 1. Verificar campo direto no pagamento (vem do SQL ou JSON) + const directUrl = (payment as any).transactionReceiptUrl || (payment as any).transaction_receipt_url; + if (directUrl && typeof directUrl === 'string' && directUrl.startsWith('http')) return directUrl; + // 2. Cross-reference com boletos (tabela SQL separada) const asaasId = payment.asaasPaymentId || (payment as any).asaas_payment_id; let boleto = null; @@ -113,8 +115,10 @@ export default function Financeiro() { ); } - if (!boleto) return null; - return (boleto as any).link_recibo || (boleto as any).transaction_receipt_url || null; + const boletoUrl = (boleto as any)?.transaction_receipt_url || (boleto as any)?.link_recibo; + if (boletoUrl && typeof boletoUrl === 'string' && boletoUrl.startsWith('http')) return boletoUrl; + + return null; }; const handleOpenReceipt = (payment: Payment) => { @@ -122,6 +126,7 @@ export default function Financeiro() { if (receiptUrl) { window.open(receiptUrl, '_blank', 'noopener,noreferrer'); } else { + // Fallback: abrir modal local com dados do pagamento setReceiptPayment(payment); } }; @@ -244,10 +249,10 @@ export default function Financeiro() {

- TOTAL DE PARCELAS + PARCELAS RESTANTES

-

- {payments.length} +

isPending(p)).length > 0 ? 'var(--color-warning)' : 'var(--color-success)' }}> + {payments.filter(p => isPending(p)).length}

@@ -307,7 +312,7 @@ export default function Financeiro() { Vencimento Valor Desconto - A Pagar + {filter === 'paid' ? 'Pago' : 'A Pagar'} Status Ação