feat(finance): eixo caixa no realizado + DFC pessoal (fases 1 e 2) - #81
Open
alanrezendeee wants to merge 4 commits into
Open
feat(finance): eixo caixa no realizado + DFC pessoal (fases 1 e 2)#81alanrezendeee wants to merge 4 commits into
alanrezendeee wants to merge 4 commits into
Conversation
Um fato, dois eixos, cada medida declara o seu: - previsto / a pagar / a receber: COMPETÊNCIA (due_date) — a obrigação pertence ao mês em que vence, paga ou não. Sem mudança - realizado: CAIXA (COALESCE(DATE(paid_at), due_date)) — o dinheiro saiu quando saiu. Parcela de dezembro antecipada em agosto passa a contar no realizado de agosto; a atrasada de junho paga em julho, no de julho Antes o sistema aplicava competência até no realizado — um regime híbrido não declarado, invisível enquanto se pagava perto do vencimento. Antecipação de parcela expôs a distorção dupla: o mês do pagamento escondia o desembolso, e o mês do vencimento mostraria 'realizado' sem dinheiro sair. Mudanças: - Summary: totais separados em duas queries, uma por eixo - MonthlySeries: dois GROUP BY (um por eixo) mesclados em memória — um lançamento pode contribuir para meses DIFERENTES nas duas medidas - Categorias e drill-down: cláusula por status (prevista→vencimento, realizada→pagamento), mantendo modal e barra idênticos por construção - fallback em due_date cobre liquidações antigas que não gravaram paid_at Sem migração e sem alteração de dado: só o pivô das agregações. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GET /finance/dashboard/cashflow?year&family_member_id Saldo inicial + entradas pagas − saídas pagas = saldo final, mês a mês, tudo no eixo caixa que a fase 1 estabeleceu. Responde a pergunta que o dashboard de compromissos não responde: quanto sobrou de verdade. - abertura = líquido de todos os fluxos realizados antes de 1º de janeiro (o caixa que o histórico registrado construiu; não é saldo bancário — o ledger conhece fluxos, não contas) - 12 meses sempre preenchidos (zeros onde não houve movimento) e saldo acumulado carregando pelos meses vazios - mesmas exclusões do dashboard: topo apenas, soft-deleted fora; realizada é o único status que move caixa Teste da identidade contábil: abertura + soma dos líquidos = fechamento, com acumulado atravessando meses sem movimento. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… caixa) O Confirm tinha um atalho: sem desconto/valor/data no body, só mudava o status — paid_at ficava NULL. O modal de despesas sempre manda a data, mas o 'Confirmar recebimento' de Receitas chama sem payload: toda receita confirmada por ali caía no fallback por vencimento, degradando em silêncio o eixo caixa das fases 1 e 2 daqui pra frente. - atalho removido: caminho único carimba paid_at (default: agora) e paid_amount_cents (pagamento integral) em toda liquidação - efeito colateral correto: confirmar lançamento cancelado agora é rejeitado (o atalho antigo permitia; a guarda sempre existiu no caminho com campos) - setStatus removido (código morto — era só o atalho que o usava) Testes: carimbo na liquidação rápida (paid_at + paid_amount + cascata com a data), rejeição de cancelada. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fase 4) Trilha (finance_entry_events, migration 000042, append-only): - confirmed/settled com paid_at e valor; reopened; cancelled com motivo; due_date_changed com vencimento original preservado (evidência de prorrogação/antecipação que o modelo não tinha) - ator: o auth injeta o user_id no context da requisição (pacote appctx, neutro — nem application→interfaces nem o inverso); rotinas automáticas ficam com actor nulo - falha na gravação do evento não derruba a operação (o pagamento já persistiu; reverter por causa do log seria pior) — vai para o slog - GET /finance/entries/:id/events - motivação: o momento da liquidação nunca foi fato próprio; updated_at é 'último toque' e foi contaminado por edições em massa. Evento não se edita Imutabilidade (lançamento realizado é fato consumado): - editar valor, vencimento, natureza ou status via PUT é rejeitado com mensagem apontando o caminho certo (Reopen/Cancelar); rótulos (descrição, notas, categoria, membro, fornecedor) continuam livres - propagação de dia na série deixa de tocar parcelas pagas (antes o 'esta e futuras' movia vencimento de realizada) Fora do escopo da trilha: origens encerradas por renegociação (evento próprio em finance_renegotiations) e cascata de itens de fatura (a ação é uma só, no pai). 9 casos de teste novos. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
Author
|
Fase 4 adicionada — trilha de eventos + imutabilidade.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fases 1 e 2 do plano de profissionalização contábil, juntas neste PR.
Fase 1 — um fato, dois eixos, cada medida declara o seu
due_date(sem mudança)COALESCE(DATE(paid_at), due_date)O sistema aplicava competência até no realizado — regime híbrido não declarado, invisível enquanto se paga perto do vencimento. A antecipação de uma parcela de financiamento expôs a distorção dupla: o mês do pagamento escondia o desembolso real, e o mês do vencimento mostraria "realizado" sem dinheiro sair.
GROUP BY(um por eixo) mesclados em memória — um lançamento pode contribuir para meses diferentes nas duas medidasdue_datepara liquidações antigas sempaid_atFase 2 — DFC pessoal
GET /finance/dashboard/cashflow?year&family_member_idSaldo inicial + entradas pagas − saídas pagas = saldo final, mês a mês. A abertura é o líquido de todos os fluxos realizados antes de 1º de janeiro — o caixa que o histórico registrado construiu (fluxos do ledger, não saldo bancário). 12 meses sempre preenchidos, saldo acumulado atravessando meses sem movimento.
Teste da identidade contábil: abertura + soma dos líquidos = fechamento.
Fase 3 — toda liquidação grava paid_at
O Confirm tinha um atalho sem carimbo: sem campos no body, só mudava o status e paid_at ficava NULL — o "Confirmar recebimento" de Receitas usa exatamente esse caminho, então o eixo caixa degradaria em silêncio daqui pra frente. Atalho removido: caminho único carimba paid_at (default: agora) e paid_amount_cents em toda liquidação. Efeito colateral correto: confirmar lançamento cancelado passa a ser rejeitado. setStatus virou código morto e foi removido.
Impacto nos dados
Nenhum — sem migração, nenhum lançamento alterado. Números exibidos mudam apenas onde mês do pagamento ≠ mês do vencimento.
Front: retech-meufin-admin #96 (mesma branch).
🤖 Generated with Claude Code