feat(financeiro): adiciona calculo dinamico local de juros e multas para exibir em tempo real
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m11s Details

This commit is contained in:
Sidney 2026-06-07 16:30:18 -03:00
parent 83720b0258
commit 7baafee2b1
2 changed files with 56 additions and 4 deletions

View File

@ -1189,6 +1189,20 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
const valorPago = Number((payment as any).valor_pago || 0); const valorPago = Number((payment as any).valor_pago || 0);
const discount = Number(payment.discount || 0); const discount = Number(payment.discount || 0);
let additions = 0;
const isOverdue = ['overdue', 'atrasado'].includes((payment.status || '').toLowerCase());
if (!isPaid && isOverdue && payment.dueDate) {
const dd = new Date(payment.dueDate + 'T00:00:00');
const tt = new Date(); tt.setHours(0,0,0,0);
if (tt > dd) {
const baseA = payment.amount - discount;
const dDays = Math.ceil((tt.getTime() - dd.getTime()) / 86400000);
const fineAmt = baseA * ((Number(payment.lateFee) || 2) / 100);
const intAmt = baseA * (((Number(payment.interest) || 1) / 30) / 100) * dDays;
additions = fineAmt + intAmt;
}
}
if (isPaid) { if (isPaid) {
const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount); const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount);
return ( return (
@ -1200,13 +1214,18 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
return ( return (
<> <>
<div className="font-bold text-slate-700 text-sm"> <div className="font-bold text-slate-700 text-sm">
R$ {payment.amount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
</div> </div>
{discount > 0 && ( {discount > 0 && (
<div className="text-[10px] text-emerald-600 font-bold"> <div className="text-[10px] text-emerald-600 font-bold">
- R$ {discount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} - R$ {discount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
</div> </div>
)} )}
{additions > 0 && (
<div className="text-[10px] text-red-500 font-bold">
+ R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} (Juros/Multa)
</div>
)}
</> </>
); );
} }
@ -1286,6 +1305,20 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
const isPaid = ['paid', 'pago', 'received', 'confirmed'].includes((payment.status || '').toLowerCase()); const isPaid = ['paid', 'pago', 'received', 'confirmed'].includes((payment.status || '').toLowerCase());
const valorPago = Number((payment as any).valor_pago || 0); const valorPago = Number((payment as any).valor_pago || 0);
const discount = Number(payment.discount || 0); const discount = Number(payment.discount || 0);
let additions = 0;
const isOverdue = ['overdue', 'atrasado'].includes((payment.status || '').toLowerCase());
if (!isPaid && isOverdue && payment.dueDate) {
const dd = new Date(payment.dueDate + 'T00:00:00');
const tt = new Date(); tt.setHours(0,0,0,0);
if (tt > dd) {
const baseA = payment.amount - discount;
const dDays = Math.ceil((tt.getTime() - dd.getTime()) / 86400000);
const fineAmt = baseA * ((Number(payment.lateFee) || 2) / 100);
const intAmt = baseA * (((Number(payment.interest) || 1) / 30) / 100) * dDays;
additions = fineAmt + intAmt;
}
}
if (isPaid) { if (isPaid) {
const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount); const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount);
@ -1298,13 +1331,18 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
return ( return (
<> <>
<div className="font-black text-slate-900 text-sm"> <div className="font-black text-slate-900 text-sm">
R$ {payment.amount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
</div> </div>
{discount > 0 && ( {discount > 0 && (
<div className="text-[10px] text-emerald-600 font-bold"> <div className="text-[10px] text-emerald-600 font-bold">
- R$ {discount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} - R$ {discount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
</div> </div>
)} )}
{additions > 0 && (
<div className="text-[10px] text-red-500 font-bold mt-0.5">
+ R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} (Multa/Juros)
</div>
)}
</> </>
); );
} }

View File

@ -163,8 +163,22 @@ export default function Financeiro() {
// Se está pago mas o banco ainda não sincronizou o valor_pago (fallback) // Se está pago mas o banco ainda não sincronizou o valor_pago (fallback)
if (isPaid) return payment.amount - (payment.discount || 0); if (isPaid) return payment.amount - (payment.discount || 0);
// Se está pendente ou atrasado, mostramos o que falta pagar (Líquido esperado) const baseAmount = payment.amount - (payment.discount || 0);
return payment.amount - (payment.discount || 0);
// Simulação Matemática de Atraso
if (status === 'overdue' && payment.dueDate) {
const dd = new Date(payment.dueDate + 'T00:00:00');
const tt = new Date(); tt.setHours(0,0,0,0);
if (tt > dd) {
const dDays = Math.ceil((tt.getTime() - dd.getTime()) / 86400000);
const fineAmt = baseAmount * ((Number(payment.lateFee) || 2) / 100);
const intAmt = baseAmount * (((Number(payment.interest) || 1) / 30) / 100) * dDays;
return baseAmount + fineAmt + intAmt;
}
}
// Se está pendente ou atrasado sem juros aplicáveis, mostramos o líquido esperado
return baseAmount;
}; };
const totalPending = payments const totalPending = payments