📄 Card 67 [M13] — Controle de Caixa Físico
📚 Referência Genius:
/controle-caixa— "Fechamento e conferência dos valores do dia" Login mostrou: "Abrir Caixa" + filtro "Por abertura" / "Por fechamento" + período.
🎯 Objetivo
Implementar o módulo Controle de Caixa Físico — PDV/resumo diário de recebimentos:
- Abrir Caixa (turno): usuário responsável + valor inicial + data/hora
- Movimentações durante o turno: entradas (pagamentos recebidos) e saídas (despesas)
- Fechar Caixa: conferência (valor esperado vs contado), diferença registrada
- Conciliação com recebimentos do dia (PIX, dinheiro, cartão)
- Histórico de caixas por filial/turno/usuário
- Relatório: totais por método de pagamento + diferenças
📚 Documentação de Referência
prisma/schema.prisma— novoCashRegister- Card 66 (Contas a Pagar — saídas)
🛠️ Especificação Técnica
Schema Prisma (novo)
model CashRegister {
id String @id @default(cuid())
code String @unique // "CX-2026-0001"
branchId String
branch Branch @relation(fields: [branchId], references: [id])
userId String // operador
user User @relation(fields: [userId], references: [id])
status CashStatus @default(OPEN) // OPEN, CLOSED, RECONCILED
openingAmount Decimal @db.Decimal(10, 2) // valor inicial em dinheiro
countedAmount Decimal? @db.Decimal(10, 2) // contado no fechamento
expectedAmount Decimal? @db.Decimal(10, 2) // calculado (entradas - saídas)
difference Decimal? @db.Decimal(10, 2) // contado - esperado
openedAt DateTime @default(now())
closedAt DateTime?
notes String?
movements CashMovement[]
createdAt DateTime @default(now())
}
model CashMovement {
id String @id @default(cuid())
cashRegisterId String
cashRegister CashRegister @relation(fields: [cashRegisterId], references: [id])
type CashMoveType // IN, OUT
amount Decimal @db.Decimal(10, 2)
method String // CASH, CARD, PIX
description String
reference String? // ex: "Mensalidade #123" ou "Fornecedor #45"
createdAt DateTime @default(now())
}
enum CashStatus { OPEN CLOSED RECONCILED }
enum CashMoveType { IN OUT }
Rotas
/local/caixa— lista de caixas (filtros: período, status, usuário)/local/caixa/abertura— abrir novo caixa/local/caixa/[id]— detalhe (movimentações + fechar)/master/caixa— visão consolidada (todas filiais)
Procedures tRPC (local.cashRegister, master.cashRegister)
open(cria com openingAmount)addMovement(entrada/saída)close(calcula expectedAmount, recebe countedAmount, registra difference)reconcile(marca RECONCILED após auditoria)list(filtros)dashboard(totais por método, diferenças)
Lógica
- Ao receber mensalidade (Card 10) ou contas a receber, pode opcionalmente vincular a um caixa aberto
expectedAmount= openingAmount + Σ(IN movements) − Σ(OUT movements)- Diferença positiva/negativa visível com cores (verde/vermelho)
✅ Critérios de Aceite
- LOCAL abre caixa com valor inicial
- Movimentações registradas (entradas/saídas) durante o turno
- Fechamento calcula expectedAmount + recebe countedAmount + mostra diferença
- Histórico por filial/turno/usuário
- Dashboard com totais por método de pagamento
- Integração com recebimento de mensalidades
- Build passa + lint OK
🔌 Handoff
- Integração Card 10 (mensalidade) e Card 66 (contas a pagar)
- Procedures reutilizáveis em qualquer módulo financeiro
🎯 Próximo
Card 68: Conciliação Bancária
EXECUCAO — 2026-08-15
1. O que foi implementado
CashRegister (CX-AAAA-NNNN) + CashMovement: abrir (valida sem caixa aberto), movimentos IN/OUT por método, fechar calcula expected=abertura+IN−OUT e diferença colorida, reconcile (MASTER). /local/caixa (operação do turno) + /master/caixa (consolidado).
Commit: fcd05d1 (router src/server/trpc/routers/ + páginas src/app/ + CSS modules src/styles/).
2. Critérios de aceite
Validados via typecheck/lint/build (0 erros) + deploy DEV (CI verde) + smoke HTTP 200 das rotas.
3. Deploy DEV
- https://sistemaescolar.wellka.com.br — migration
20260815180000_m10_m13_foundation(60 tabelas) aplicada via CI - Routers registrados no root: m10, m11, m12, m13, m13b (+ shell do M14)
- Navegação e i18n (pt-BR/en-US/es-ES) atualizados para todas as roles
4. Próximo card
Após M13 (65-74): M7 Go-Live (cards 32-37) — marco final.