// Relatório mensal completo (todas as sessões + insights + sugestões) — imprimível function RelatorioMensalPage({ state, refKey, onVoltar }) { const fmt = window.fmtBRLString; const [ys, ms] = (refKey || "2026-06").split("-"); const year = Number(ys), month = Number(ms) - 1; const refLabel = `${window.MESES_FULL[month]}/${year}`; const txs = state.transactions || []; const monthTxs = window.txByMonth(txs, year, month); const plano = window.computePlano(txs, state.aggregates, year, month); const income = plano.income; const expense = window.sumExpense(monthTxs) || window.aggExpenseForMonth(state.aggregates, year, month); const classes = window.byClasse(monthTxs); const cats = window.byCategory(monthTxs.filter(t => t.type === "Despesa")).slice(0, 6); const p = state.patrimonio || {}; const tot = window.patrimonioTotais(p, state.dividas); const custoFixo = window.custoFixoEssencialMensal(txs); const reservaSaldo = (p.saldos || []).filter(s => s.reserva).reduce((s, a) => s + Number(a.valor || 0), 0); const reservaAlvo = custoFixo * ((state.reserva || {}).mesesAlvo || 6); const apo = window.calcAposentadoria(state.aposentadoria || { rendaMensalDesejada: 0 }, tot.financeiro); const apoGap = Math.max(0, (apo.alvo || 0) - (apo.projecao || 0)); const objetivos = state.objetivos || []; const objPess = state.objetivosPessoais || {}; const objPessSel = (window.OBJ_PESSOAIS_CATALOGO || []).filter(i => objPess[i.id] && objPess[i.id].selecionado); const seguros = state.seguros || []; const dividas = state.dividas || []; const dividaTotal = dividas.reduce((s, d) => s + Number(d.saldo || d.valor || 0), 0); const entrega = ((state.fechamento || {}).entregas || {})[refKey] || {}; // ---- Lei de Jim Rohn (70/10/10/10) ---- const bmap = {}; plano.buckets.forEach(b => { bmap[b.key] = b; }); const rohn = window.PLANO_ORDER.map(k => { const b = bmap[k]; const def = window.PLANO[k]; const target = income * def.pct; const used = b ? b.used : 0; const pct = target > 0 ? used / target : 0; const avaliado = target > 0; const ok = avaliado && (k === "gastos" ? used <= target * 1.02 : used >= target * 0.9); return { key: k, label: def.label, alvoPct: def.pct * 100, target, used, pct, ok, avaliado }; }); const semDados = income <= 0; const avaliados = rohn.filter(r => r.avaliado); const rohnOk = avaliados.filter(r => r.ok).length; const nota = avaliados.length ? Math.round((rohnOk / avaliados.length) * 100) : null; const saldoMes = income - expense; const taxaPoupanca = income > 0 ? (income - (bmap.gastos ? bmap.gastos.used : expense)) / income : 0; const veredito = semDados ? { t: "Sem dados suficientes", c: "warn", d: `Não há receitas lançadas em ${refLabel}. Registre as receitas e despesas do mês para que o diagnóstico do 70/10/10/10 possa ser calculado.` } : nota >= 100 ? { t: "No caminho", c: "ok", d: "Todos os quatro pilares do 70/10/10/10 foram respeitados neste mês." } : nota >= 50 ? { t: "Parcialmente no caminho", c: "warn", d: "Parte dos pilares foi cumprida — os desvios abaixo precisam de correção no próximo ciclo." } : { t: "Fora do caminho", c: "bad", d: "A maioria dos pilares ficou fora do alvo. É prioridade reorganizar o mês seguinte." }; // ---- Sugestões assertivas ---- const sug = []; if (semDados) sug.push(`Lance as receitas e despesas de ${refLabel} no Orçamento — sem isso o fechamento do mês não pode ser avaliado.`); const g = bmap.gastos; if (!semDados && g && g.used > income * 0.70) { const excesso = g.used - income * 0.70; sug.push(`Reduza ${fmt(excesso)} de gastos até o próximo fechamento: comece pelas despesas variáveis e pelos gastos marcados como redutíveis.`); } ["caridade", "ativo", "passivo"].forEach(k => { const b = bmap[k], def = window.PLANO[k]; if (!semDados && b && b.used < income * def.pct * 0.9) { sug.push(`Aporte ${fmt(income * def.pct - b.used)} em ${def.label} para fechar os 10% do mês — programe débito automático no dia do recebimento.`); } }); if (reservaSaldo < reservaAlvo) { const falta = reservaAlvo - reservaSaldo; const aporte = income * 0.1; if (aporte >= 100) { const meses = Math.max(1, Math.ceil(falta / aporte)); sug.push(`Reserva de emergência ${fmt(falta)} abaixo do alvo (${fmt(reservaAlvo)}). Mantendo 10% da renda, ela é completada em ~${meses} mês(es).`); } else { sug.push(`Reserva de emergência ${fmt(falta)} abaixo do alvo (${fmt(reservaAlvo)}) — defina um aporte mensal fixo para fechar essa diferença.`); } } if (dividaTotal > 0) sug.push(`Priorize a quitação de ${fmt(dividaTotal)} em dívidas — amortize primeiro a de maior taxa e evite novas parcelas neste ciclo.`); if (seguros.length === 0) sug.push("Nenhuma proteção cadastrada: contrate/registre seguro de vida e de renda antes de ampliar investimentos."); if (apoGap > 0) sug.push(`Aposentadoria: a projeção atual fica ${fmt(apoGap)} abaixo do capital necessário. Aporte mensal recomendado: ${fmt(apo.aporteNecessario || 0)}.`); if (objPessSel.length === 0) sug.push("Cadastre seus objetivos pessoais na primeira etapa — sem objetivo definido não há como priorizar o orçamento."); objetivos.filter(o => o.alvo > 0 && o.acumulado < o.alvo).slice(0, 2).forEach(o => { sug.push(`Objetivo "${o.nome}": faltam ${fmt(o.alvo - o.acumulado)} até ${o.prazo ? o.prazo.split("-").reverse().join("/") : "o prazo"} — reserve uma parcela fixa mensal para ele.`); }); if (taxaPoupanca >= 0.3) sug.push("Taxa de poupança acima de 30%: avalie diversificar novos aportes entre renda fixa e ativos de longo prazo."); if (sug.length === 0) sug.push("Mês equilibrado: mantenha o mesmo padrão de aportes e revise as metas de longo prazo no próximo trimestre."); function Sec({ title, scope, children }) { return (

{title}

{scope && {scope}}
{children}
); } const Linha = ({ k, v }) =>
{k}{v}
; return (

📄 Relatório do mês — {refLabel}

Prestação de contas consolidada de todas as etapas do plano.
{onVoltar && }

Prestação de contas

Relatório mensal consolidado — {refLabel}

Cliente{(state.user || {}).name || "—"}
Mês de referência{refLabel}
Data de fechamentodia {(state.fechamento || {}).dia || 5}
Entrega registrada em{entrega.dataEntrega ? entrega.dataEntrega.split("-").reverse().join("/") : "—"}
{semDados ? "—" : nota}{semDados ? "sem nota" : "/100"}
{veredito.t}

{veredito.d}

Renda {fmt(income)} Gastos {fmt(expense)} Saldo {fmt(saldoMes)} Taxa de poupança {semDados ? "—" : (taxaPoupanca * 100).toFixed(0) + "%"}
{rohn.map(r => (
{r.label} {r.alvoPct}%
{fmt(r.used)} {r.avaliado ? `de ${fmt(r.target)}` : "sem alvo (renda não lançada)"} {!r.avaliado ? "n/d" : r.ok ? "cumprido" : r.key === "gastos" ? "excedeu" : "abaixo"}
))}

Por classe

{classes.length ? classes.map(c => ) :

Sem lançamentos classificados neste mês.

}

Maiores categorias

{cats.length ? cats.map(c => ) :

Sem despesas detalhadas.

}
{objPessSel.length ? objPessSel.map(i => { const d = objPess[i.id] || {}; return (
{i.id === "outro" && d.titulo ? d.titulo : i.nome} {d.inicio ? d.inicio.split("-").reverse().join("/") : "sem início"} → {d.fim ? d.fim.split("-").reverse().join("/") : "sem prazo"} {d.motivo &&

{d.motivo}

}
); }) :

Nenhum objetivo pessoal selecionado.

}
{objetivos.length ? objetivos.map(o => (
{o.icone} {o.nome} {fmt(o.acumulado)} / {fmt(o.alvo)} {o.alvo > 0 ? Math.round(o.acumulado / o.alvo * 100) : 0}%
)) :

Nenhum objetivo cadastrado.

}
{seguros.length ? seguros.map(s => ( )) :

Nenhuma proteção cadastrada.

}
= reservaAlvo ? "Situação" : "Falta"} v={reservaSaldo >= reservaAlvo ? "Completa" : fmt(reservaAlvo - reservaSaldo)}/> {entrega.nota ? (

Como foi o mês: {entrega.nota}

{entrega.pontos &&

Pontos positivos: {entrega.pontos}

} {entrega.ajustes &&

Ajustes: {entrega.ajustes}

}
) :

Relato ainda não registrado para {refLabel}.

}
    {sug.map((s, i) =>
  1. {s}
  2. )}
); } Object.assign(window, { RelatorioMensalPage });