Carteira de saldo sem furo contábil
Equipe AltiviaCloud · 6 de setembro de 2026 · 4 min de leitura
Ler o saldo, calcular na aplicação e gravar o resultado é como o dinheiro some. O saldo é consequência do extrato, não a verdade.
Sistema de saldo parece simples: uma coluna com o valor, soma quando entra, subtrai quando sai. É assim que quase todo mundo começa, e é assim que aparece o primeiro furo — dinheiro que sumiu, ou saldo que apareceu do nada, e ninguém consegue explicar de onde veio.
O erro que gera furo
UPDATE carteiras SET saldo = 42.50 WHERE id = ...
O problema é ler o saldo, calcular na aplicação e gravar o resultado. Entre a leitura e a escrita, outra operação pode ter mexido no mesmo valor — e ela é sobrescrita.
Dois pedidos simultâneos de dez reais, saldo de cem: ambos leem cem, ambos calculam noventa, ambos gravam noventa. Saiu vinte, o saldo caiu dez.
A correção é deixar o banco fazer a conta:
UPDATE carteiras SET saldo = saldo - 10 WHERE id = ... AND saldo >= 10
Duas coisas mudam. A subtração acontece no banco, sobre o valor atual. E a condição de saldo suficiente faz parte da mesma operação — não é uma verificação anterior que pode ficar desatualizada.
Se essa operação afetar zero linhas, o saldo era insuficiente. É o retorno, não uma leitura posterior, que decide.
O saldo é derivado, não a verdade
O modelo que sobrevive a auditoria tem duas peças:
Um extrato imutável. Cada movimento é uma linha nova: tipo, valor, momento, e o que originou. Nada é atualizado nem apagado.
O saldo como consequência. Ou é a soma do extrato, ou é uma coluna mantida em sincronia — mas o extrato é quem manda.
Isso muda o que acontece quando alguém pergunta "por que meu saldo está diferente do que eu esperava". Com só a coluna, a resposta é um encolher de ombros. Com o extrato, você mostra linha por linha.
E permite a conferência que revela furo: somar o extrato e comparar com a coluna. Se divergiu, você tem um defeito — e descobre antes do cliente.
Todo movimento precisa de origem
Cada linha do extrato aponta para o que a causou: o pedido, a cobrança, o estorno. Sem essa ligação, você tem um débito de três reais sem saber de onde veio.
É também o que permite responder à pergunta que mais chega no suporte: "cobraram duas vezes". Com a origem registrada, você vê em segundos se são dois movimentos do mesmo pedido — que é defeito — ou dois pedidos distintos — que não é.
Crédito duplicado: o furo mais caro
O aviso de pagamento chega mais de uma vez. Todo provedor entrega ao menos uma vez, nenhum entrega exatamente uma vez.
A guarda que parece resolver e não resolve:
if (cobranca.status !== 'PAGA') { creditar(); marcarComoPaga(); }
Dois avisos que chegam ao mesmo tempo passam os dois pela verificação antes de qualquer um marcar. Crédito em dobro.
O que resolve é fazer a transição de status ser a primeira operação, condicional, dentro da mesma transação:
UPDATE cobrancas SET status = 'PAGA'
WHERE id = ... AND status <> 'PAGA'
Quem afetar uma linha ganhou a corrida e credita. Quem afetar zero desiste em silêncio. O banco decide, não a aplicação.
Estorno é lançamento, não subtração
A tentação é apagar o débito ou somar de volta na coluna. Nos dois casos o histórico deixa de contar o que aconteceu.
Estorno é uma linha nova, positiva, apontando para o movimento original. O extrato passa a mostrar o débito e a devolução — que é exatamente o que o cliente quer ver quando reclama.
Trabalhe com inteiros
Valor monetário em ponto flutuante acumula erro. 0.1 + 0.2 não dá 0.3, e isso vira centavo perdido em volume.
Duas saídas: tipo decimal do banco, ou guardar em centavos como inteiro. As duas funcionam; misturar as duas não.
O cuidado extra é na conversão para exibição, que é onde o arredondamento entra — e onde a soma da tela pode deixar de bater com a soma real.
Três conferências que valem a pena
Extrato contra coluna. Rodando periodicamente, alerta quando divergir.
Movimento sem origem. Deveria ser sempre zero.
Saldo negativo. Se a condição de saldo suficiente está correta, é impossível. Se aparecer, existe um caminho de débito que não passa por ela.
As três são consultas simples e pegam o problema antes do cliente.
O outro lado disso, do ponto de vista do meio de pagamento, está em Pix como meio de pagamento de API, e o mecanismo de defesa contra aviso repetido, em idempotência em webhook de pagamento.
Na AltiviaCloud o saldo segue essas regras: o débito é condição do próprio UPDATE, e o pedido que não recebe SMS é estornado sozinho. Como a cobrança funciona está em preços.