v0.74.0
AFService Map v0.74.0 — Módulo financeiro
Backup/ponto de rollback desta rodada: tag v0.73.1. Trabalho feito
diretamente por mim (Claude), a pedido do usuário ("vamos criar 1 base
de financeiro, para controle de pagamento etc dos meus clientes").
Com migration (apps.billing.0001_initial, roda automaticamente no
apply).
Contexto
O sistema não tinha nenhum controle de pagamento — os únicos dados
vindos do IXCSoft ficam soltos em raw_data (JSON), sem estrutura de
fatura, mensalidade ou pagamento em lugar nenhum. Também não existia uma
página de detalhe por cliente — o único lugar onde um cliente aparecia
era como popup no mapa. Como a plataforma atende empresa com ou sem
ERP, o cadastro financeiro do cliente não podia depender do
AccessPoint (que só existe quando há sincronização) — é um cadastro
próprio, com vínculo opcional.
Decisões confirmadas com o usuário antes de implementar
Perguntei diretamente antes de desenhar o banco, pra não ter que
redesenhar depois:
- Controle manual agora, com o schema pronto pra gateway depois
(Efí, Inter, Mercado Pago — escolhido por empresa no futuro). Os
campos existem, mas nenhuma integração real entrou nesta rodada. - Página de detalhe do cliente nova, em vez de um botão no popup do
mapa. - Mensalidade recorrente automática via Celery Beat, em vez de
lançamento manual mês a mês. - Mesmo acesso EDIT de hoje — sem controle de permissão novo.
O que entrou
Cadastro de cliente (apps.billing.Customer)
Nome, documento, e-mail, telefone, endereço, situação
(ativo/inativo/suspenso), mensalidade e dia de vencimento (opcionais —
sem eles, o cliente só recebe lançamento manual), e um vínculo opcional
com um AccessPoint já existente (pra quem já usa mapa/ERP).
Mensalidade recorrente automática
apps.billing.tasks.generate_monthly_invoices, agendada de hora em hora
no CELERY_BEAT_SCHEDULE (config/settings.py): para cada cliente com
mensalidade ativa, cria a fatura (Invoice) do mês corrente se ainda
não existir. Idempotente de verdade — protegida por
UniqueConstraint(customer, reference_month), então rodar de novo (ou
com mais frequência) nunca duplica fatura. O dia de vencimento é
ajustado automaticamente pra sempre existir no mês (dia 31 cadastrado
vira o último dia de fevereiro, por exemplo).
apps.billing.tasks.mark_overdue_invoices, mesmo agendamento: fatura
pendente com vencimento no passado vira "Atrasada" sozinha.
Registro de pagamento
Cada fatura aceita um ou mais pagamentos (Payment) — dinheiro, PIX,
transferência, cartão ou outro, com observação e quem registrou. A
fatura só fecha como "Paga" quando a soma dos pagamentos atinge o valor
devido; pagamento parcial fica registrado sem fechar a fatura.
Página de cliente nova
- Lista (
/painel/financeiro/): clientes da empresa, busca por
nome, resumo (faturas atrasadas, pendentes, pagas no mês). - Detalhe (
/painel/financeiro/<id>/): dados do cliente, histórico
completo de faturas com status, e um formulário de pagamento pra cada
fatura ainda em aberto. - Menu lateral ganhou o item "Financeiro" (mesma regra de acesso de
"Alertas": some para empresa em modo projetista).
Reservado para o futuro, não integrado
Invoice.gateway_provider (nenhum/Efí/Inter/Mercado Pago) e
Invoice.gateway_charge_id existem no schema desde já, mas nenhuma
chamada de API, webhook ou geração de boleto/PIX cobrável de verdade
entrou nesta versão — só evita ter que alterar o banco quando isso for
implementado.
O que ficou de fora, de propósito
- Integração real de gateway de pagamento.
- Botão de financeiro no popup do mapa (o usuário escolheu a página de
detalhe nova). - Visão financeira consolidada entre empresas na "Visão da plataforma"
— fica igual às outras seções, só por empresa.
Verificação feita
clamp_due_day/due_date_for(o cálculo que garante um dia de
vencimento sempre válido no mês, incluindo fevereiro e meses de 30
dias) são funções puras, sem banco — executei de verdade via
script Python direto nesta sessão (mesmo método já usado com
apps/snmp_monitoring/link_status.pyeste ano): 5 asserções, todas
passaram, incluindo o caso de fevereiro bissexto vs. não-bissexto.python -m py_compileem todos os arquivos Python novos
(apps/billing/*) e nos tocados (config/settings.py,
config/urls.py).- Migration escrita à mão, campo a campo, contra
models.py(sem GDAL
neste ambiente de preparação — não dá pra rodarmakemigrations).
Dependências (core.0013_dashboard_widget_layout,
access.0002_add_ftth_fields) conferidas como as últimas migrations
de cada app antes de referenciá-las. - Chaves do
static/css/app.cssbalanceadas (276/276, só 3 classes
novas pequenas — reaproveitei.overview-table,.sync-pill,
.metric-card,.panel,.platform-forme.info-listjá
existentes em vez de criar CSS novo pra tudo). {% if %}/{% endif %}/{% for %}/{% endfor %}/{% block %}/
{% endblock %}balanceados nos 3 templates novos
(templates/billing/) e nobase.htmltocado.- YAML do
docker-compose.ymlválido.
manage.py check, manage.py migrate, manage.py test e o teste
visual real dependem de banco, GDAL e navegador — não rodam neste
ambiente de preparação. Precisam ser feitos no servidor.
Atualização
Execute apply no servidor — esta versão tem migration
(apps.billing.0001_initial), roda automaticamente. Depois, um
Ctrl+F5 no navegador.
Teste sugerido: abrir "Financeiro" no menu, cadastrar um cliente com
mensalidade e dia de vencimento, confirmar que a fatura do mês aparece
(pode rodar generate_monthly_invoices manualmente via
manage.py shell na primeira vez, já que o Celery Beat só passa a rodar
a cada hora a partir do próximo ciclo), registrar um pagamento parcial e
depois o restante, e confirmar que a fatura vira "Paga" só quando o
total bate.