Skip to content

v0.76.0

Latest

Choose a tag to compare

@adrianfiio adrianfiio released this 02 Aug 13:39

AFService Map v0.76.0 — Correção de arquitetura do financeiro

Backup/ponto de rollback: tag v0.75.1. Trabalho feito diretamente por
mim (Claude), a partir da correção explícita mandada pelo usuário:
"Os clientes (Provedores ISP e Projetistas) NÃO criam clientes e NÃO
gerenciam outros usuários em seus painéis. Eles são os meus clientes
finais. Quem cria e gerencia tudo sou eu, no painel Superadmin."
Com migration (remove o model Customer por completo).

O erro de modelo, corrigido

Desde a v0.74.0 eu tinha construído o financeiro assumindo que cada
Provedor ISP cobraria os próprios assinantes de internet — por
isso a v0.75.1 chegou a ligar o financeiro aos clientes já sincronizados
do IXCSoft (IXCCustomer). Estava errado: quem é cobrado nesta
plataforma é a empresa cliente da AFService (Provedor ISP ou
Projetista) — a mensalidade é pela licença/uso do sistema, não pela
internet que o provedor vende aos assinantes dele. Isso nunca teve
nenhum dado real (a funcionalidade tinha dias, e todos os prints
mostravam "nenhum cliente cadastrado"), então a correção pôde remover o
model antigo sem migração de dado nenhuma.

O que muda

Painel do cliente (Provedor ISP / Projetista) — só consulta

Removido por completo: botão "Novo cliente", cadastro, edição e
detalhe por cliente. O painel agora é só leitura: mensalidade, dia de
vencimento, o que está em aberto, atrasado e pago, histórico de faturas,
exportação em CSV. Continua exigindo CompanyMembership.role == EDIT
perfil VIEW não acessa, mesma regra restrita de antes (essa parte já
estava certa, não mudou).

Painel Superadmin — único lugar que cadastra e gerencia

Já existia desde a v0.75.0 o cadastro de empresa (Provedor/Projetista +
primeiro usuário responsável) fora do Django Admin — isso continua
igual. O que entrou agora, por empresa
(/painel/plataforma/empresas/<id>/financeiro/):

  • Editar assinatura — mensalidade, dia de vencimento, se gera
    cobrança automática.
  • Lançar cobrança manual avulsa — fatura fora do ciclo mensal
    automático, pra qualquer cobrança pontual.
  • Registrar pagamento por fatura em aberto.
  • Controle de status: Reativar, Bloquear, Cancelar, Desativar
    empresa, Excluir. "Excluir" não apaga nada do banco — desativa a
    empresa e cancela a assinatura junto, mesma filosofia não-destrutiva
    já usada no resto do sistema (nunca apaga equipamento, cabo, fusão
    etc.). Reversível pela mesma tela.
  • Exportar CSV — por empresa e consolidado de todas as empresas.

"Liberação de confiança"

Botão no painel do cliente (e na tela de bloqueio): concede mais 2
dias de acesso
mesmo com a assinatura bloqueada/cancelada. Limitado a
1 uso por mês corrido, validado no servidor
(apps.billing.services.request_trust_release — checa
TrustRelease.objects.filter(company=..., created_at__year=.., created_at__month=..)
antes de conceder, não só desabilita o botão na tela).

Bloqueio de acesso de verdade

Novo middleware apps.billing.middleware.SubscriptionAccessMiddleware:
quando a assinatura de uma empresa está bloqueada ou cancelada e não há
liberação de confiança em vigor, qualquer usuário dessa empresa (exceto
Superadmin, que nunca é afetado) é redirecionado pra uma tela de "conta
bloqueada" em qualquer página que tente acessar — login, logout,
arquivos estáticos, /admin/ e /api/ ficam de fora do bloqueio.

Decisão de segurança mais importante desta rodada: empresa sem
CompanySubscription cadastrada (hoje, a imensa maioria — o recurso é
nascendo agora) nunca é bloqueada. O bloqueio só passa a valer
quando o Superadmin bloqueia/cancela explicitamente pela tela de
financeiro daquela empresa. Testei essa regra como função pura antes de
sequer escrever o middleware (ver seção de verificação) — não queria
correr o risco de travar todo mundo fora do sistema por um bug de dia
1.

O que ficou de fora, de propósito

  • Chamada real a gateway de pagamento — só a tela de credencial
    (já existia desde a v0.75.0), sem integração de verdade.
  • Cobrança automática puxando o gateway quando a fatura vence — a
    geração de fatura recorrente continua automática (Celery Beat), mas
    "cobrar" ainda é manual (Superadmin registra o pagamento recebido).

Verificação feita

  • python -m py_compile em todos os arquivos tocados/novos.
  • is_access_blocked e has_trust_release_this_month são funções
    puras, sem banco — executei de verdade
    via script Python direto:
    6 asserções pra is_access_blocked (incluindo o caso crítico "sem
    assinatura cadastrada nunca bloqueia", "bloqueada mas com carência no
    futuro não bloqueia", "cancelada sem carência bloqueia") e 4 pra
    has_trust_release_this_month (incluindo mês/ano diferentes) — todas
    passaram.
  • Migration revisada campo a campo (sem GDAL neste ambiente de
    preparação): ordem correta — remove a constraint única, depois o
    índice, depois o campo customer da fatura, só então apaga o model
    Customer inteiro. Nomes de constraint/índice conferidos contra a
    migration 0001_initial.py que os criou, pra garantir que bate
    exatamente com o que existe no banco.
  • Chaves do static/css/app.css balanceadas (282/282).
  • {% if %}/{% endif %}/{% for %}/{% endfor %}/{% block %}/
    {% endblock %} balanceados em todos os templates tocados e novos.
  • git diff --check limpo.
  • Grep no projeto inteiro confirmando que nenhuma referência solta a
    Customer/billing-customers/billing-customer-* sobrou fora das
    migrations antigas (onde é esperado — são registro histórico).

manage.py check, manage.py migrate, manage.py test e o teste
real dependem de banco, GDAL e navegador — não rodam neste ambiente de
preparação.

Atualização

Execute apply no servidor — esta versão tem migration (remove o
model Customer inteiro). Depois, um Ctrl+F5 no navegador.

Teste sugerido: como Superadmin, abrir o financeiro de uma empresa de
teste, lançar uma cobrança manual e registrar o pagamento; bloquear a
assinatura dessa empresa e confirmar (logado como usuário EDIT dela)
que qualquer página redireciona pra "conta bloqueada"; pedir liberação
de confiança e confirmar os +2 dias de acesso; tentar pedir de novo no
mesmo mês e confirmar que é bloqueado; confirmar que um usuário VIEW
continua sem acessar /painel/financeiro/ de forma nenhuma; confirmar
que uma empresa qualquer sem assinatura configurada continua
acessando o sistema normalmente (fail-safe).