v1.38.0 - Projeção de Saldo considera transações em atraso + alerta visual

This commit is contained in:
marcoitaloesp-ai 2025-12-15 16:57:26 +00:00 committed by GitHub
parent b9592fc915
commit f4a33b88bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 72 additions and 12 deletions

View File

@ -5,6 +5,18 @@ O formato segue [Keep a Changelog](https://keepachangelog.com/pt-BR/).
Este projeto adota [Versionamento Semântico](https://semver.org/pt-BR/).
## [1.38.0] - 2025-12-15
### Added
- **Projeção de Saldo** - Agora considera transações em atraso
- Backend busca todas as transações pendentes (incluindo atrasadas)
- Processa transações atrasadas ANTES do ponto inicial da projeção
- Adiciona informações de transações em atraso no summary da API
- Frontend exibe alerta amarelo quando há transações em atraso incluídas
- Alerta mostra quantidade de transações e impacto no saldo
- Traduções completas: overdueIncluded, overdueTransactions, includedInProjection (pt-BR, en, es)
- Melhora precisão da projeção ao incluir todas as pendências
## [1.37.0] - 2025-12-15
### Added

View File

@ -1 +1 @@
1.37.0
1.38.0

View File

@ -942,29 +942,45 @@ public function projectionChart(Request $request)
ORDER BY li.due_date
", [$this->userId, $today->toDateString(), $endDate->toDateString()]);
// Buscar transações agendadas/pendentes
// Buscar transações agendadas/pendentes (incluindo atrasadas)
$scheduledTransactions = DB::select("
SELECT
t.effective_date as date,
t.amount,
t.type,
COALESCE(a.currency, 'EUR') as currency
COALESCE(a.currency, 'EUR') as currency,
CASE WHEN t.effective_date < ? THEN 1 ELSE 0 END as is_overdue
FROM transactions t
LEFT JOIN accounts a ON t.account_id = a.id
WHERE t.user_id = ?
AND t.status IN ('pending', 'scheduled')
AND t.effective_date >= ?
AND t.effective_date <= ?
AND t.deleted_at IS NULL
ORDER BY t.effective_date
", [$this->userId, $today->toDateString(), $endDate->toDateString()]);
", [$today->toDateString(), $this->userId, $endDate->toDateString()]);
// Ponto inicial
// Separar transações atrasadas para processar primeiro
$overdueTransactions = array_filter($scheduledTransactions, fn($tx) => $tx->is_overdue);
$futureTransactions = array_filter($scheduledTransactions, fn($tx) => !$tx->is_overdue);
// Processar transações atrasadas ANTES do ponto inicial
foreach ($overdueTransactions as $tx) {
$amount = $this->convertToPrimaryCurrency(abs($tx->amount), $tx->currency);
if ($tx->type === 'credit') {
$currentBalance += $amount;
} else {
$currentBalance -= $amount;
}
$runningBalance = $currentBalance;
}
// Ponto inicial (já inclui o impacto das transações atrasadas)
$dataPoints[] = [
'date' => $today->toDateString(),
'balance' => round($runningBalance, 2),
'label' => $today->format('d/m'),
'isToday' => true,
'has_overdue' => count($overdueTransactions) > 0,
];
// Gerar pontos até a data final
@ -1001,8 +1017,8 @@ public function projectionChart(Request $request)
}
}
// Somar transações agendadas neste período
foreach ($scheduledTransactions as $tx) {
// Somar transações agendadas neste período (apenas futuras)
foreach ($futureTransactions as $tx) {
if ($tx->date > $periodStart && $tx->date <= $periodEnd) {
$amount = $this->convertToPrimaryCurrency(abs($tx->amount), $tx->currency);
if ($tx->type === 'credit') {
@ -1048,6 +1064,11 @@ public function projectionChart(Request $request)
'change' => round($finalBalance - $currentBalance, 2),
'change_percent' => $currentBalance != 0 ? round((($finalBalance - $currentBalance) / abs($currentBalance)) * 100, 1) : 0,
'negative_month' => $negativeMonth,
'overdue_count' => count($overdueTransactions),
'overdue_impact' => round(array_reduce($overdueTransactions, function($carry, $tx) {
$amount = $this->convertToPrimaryCurrency(abs($tx->amount), $tx->currency);
return $carry + ($tx->type === 'credit' ? $amount : -$amount);
}, 0), 2),
],
'period' => [
'start' => $today->toDateString(),

View File

@ -228,7 +228,24 @@ const BalanceProjectionChart = () => {
<div className="card-body">
{/* Summary Stats */}
{summary && (
<div className="row g-3 mb-4">
<>
{/* Alert if overdue transactions included */}
{summary.overdue_count > 0 && (
<div className="alert alert-warning d-flex align-items-center mb-3" role="alert">
<i className="bi bi-exclamation-circle-fill me-2"></i>
<div>
<strong>{t('reports.projectionChart.overdueIncluded') || 'Atenção'}:</strong>{' '}
{summary.overdue_count} {t('reports.projectionChart.overdueTransactions') || 'transação(ões) em atraso'}{' '}
{t('reports.projectionChart.includedInProjection') || 'já incluída(s) no saldo atual'}.
{' '}
<span className={summary.overdue_impact < 0 ? 'text-danger fw-bold' : 'text-success fw-bold'}>
({summary.overdue_impact >= 0 ? '+' : ''}{currency(summary.overdue_impact, data?.currency)})
</span>
</div>
</div>
)}
<div className="row g-3 mb-4">
<div className="col-6 col-md-3">
<div className="p-3 rounded bg-slate-700">
<small className="text-slate-400 d-block">{t('reports.projectionChart.currentBalance') || 'Saldo Atual'}</small>
@ -262,6 +279,7 @@ const BalanceProjectionChart = () => {
</div>
</div>
</div>
</>
)}
{/* Alert if negative balance predicted */}

View File

@ -1922,7 +1922,10 @@
"2months": "2 months",
"3months": "3 months",
"6months": "6 months",
"12months": "12 months"
"12months": "12 months",
"overdueIncluded": "Overdue Transactions Included",
"overdueTransactions": "overdue transaction(s)",
"includedInProjection": "already included in balance projection"
}
},
"months": {

View File

@ -1905,7 +1905,10 @@
"2months": "2 meses",
"3months": "3 meses",
"6months": "6 meses",
"12months": "12 meses"
"12months": "12 meses",
"overdueIncluded": "Transacciones Vencidas Incluidas",
"overdueTransactions": "transacción(es) vencida(s)",
"includedInProjection": "ya incluida(s) en la proyección del saldo"
}
},
"months": {

View File

@ -1924,7 +1924,10 @@
"2months": "2 meses",
"3months": "3 meses",
"6months": "6 meses",
"12months": "12 meses"
"12months": "12 meses",
"overdueIncluded": "Transações em Atraso Incluídas",
"overdueTransactions": "transação(ões) em atraso",
"includedInProjection": "já incluída(s) na projeção do saldo"
}
},
"months": {