Skip to content

v0.75.0

Choose a tag to compare

@adrianfiio adrianfiio released this 02 Aug 13:00

AFService Map v0.75.0 — ACL do financeiro e painel Superadmin

Backup/ponto de rollback: tag v0.74.0. Trabalho feito diretamente por
mim (Claude), a partir de uma especificação de perfis de acesso e telas
de Superadmin que o usuário mandou. Com migration
(apps.billing.0002_gateway_configuration).

O que já estava pronto (verificado antes de escrever qualquer código)

Antes de implementar, conferi apps/billing/views.py (da v0.74.0) contra
a especificação recebida. A regra de acesso pros perfis de empresa já
estava completa:

  • _require_billing_company/_editable_company já restringiam o
    financeiro a CompanyMembership.role == EDIT — perfil VIEW já era
    bloqueado por completo, redirecionado com mensagem, sem exceção.
  • Essa regra já não dependia do tipo da empresa (Provedor/Projetista) —
    um EDIT de qualquer tipo vê o próprio financeiro, um VIEW de qualquer
    tipo não vê nenhum. Não criei papéis novos ("ISP Editor", "Projetista
    View" etc.) porque o CompanyMembership.Role genérico já combinado
    com Company.company_type entrega exatamente essa regra sem duplicar
    enum.

O que realmente faltava, e é o conteúdo desta versão:

1. Superadmin acessa o financeiro de qualquer empresa

_require_billing_company (renomeada pra _require_list_company/
_customer_for_request) antes bloqueava superusuário por completo,
mandando "acessar como usuário da empresa" — o que não fazia sentido
pra Superadmin, que não tem (nem deveria ter) vínculo de equipe em
nenhuma empresa.

Agora:

  • Lista e criação de cliente: superusuário resolve a empresa via
    ?empresa=<id> na query string — vindo do link "Financeiro →" que
    cada linha da tabela de empresas ganhou na Visão da plataforma.
  • Detalhe, edição e pagamento (rotas que já têm um pk de cliente):
    superusuário não precisa nem do parâmetro — o cliente é buscado pelo
    pk e a empresa dele é lida diretamente do próprio registro.
  • Usuário comum nunca tem ?empresa= respeitado — a resolução dele
    continua 100% baseada no próprio vínculo CompanyMembership, a query
    string é ignorada em todo o resto do módulo. Não abre brecha de
    autorização entre empresas.
  • Cliente de outra empresa continua dando 404 pra usuário comum (nunca
    200 com "acesso negado") — não revela que o registro existe em outro
    lugar, mesmo padrão de segurança já usado no resto do sistema.

2. Cadastro de empresa pelo Superadmin, fora do Django Admin

Busquei em todo apps/core por Company.objects.create antes de
escrever qualquer coisa: não existia nenhum fluxo em-app pra criar
uma empresa do zero. company_onboarding (o único fluxo parecido) exige
que a CompanyMembership já exista — é o próprio usuário da empresa
preenchendo os dados dela depois de já ter sido criada (hoje, só via
/admin/).

Tela nova em painel/plataforma/empresas/novo/
(SuperadminCompanyForm, apps/core/forms.py): cria a empresa e o
primeiro usuário responsável numa única transação —

  • Dados da empresa (nome, documento, contato, endereço) — mesmos campos
    de CompanyOnboardingForm.
  • Tipo (Provedor/Projetista) e modo de operação (ERP/manual)
    definidos na hora, não depois.
  • Usuário responsável (nome, usuário de acesso, senha — mesma validação
    de força de senha e unicidade de CompanyTeamMemberForm) com nível
    de acesso
    (VIEW/EDIT) escolhido já no cadastro.
  • slug gerado automaticamente a partir do nome (antes só dava pra
    preencher à mão no admin).

3. Configuração de gateway de pagamento centralizada

Novo model CompanyPaymentGatewayConfiguration
(apps/billing/models.py): uma credencial por empresa, provedor
(nenhum/Efí/Inter/Mercado Pago — reaproveita o enum GatewayProvider
existente desde a v0.74.0), modo sandbox, ativo/inativo.

A credencial em si (client_id/client_secret/access_token — três
campos genéricos, cobrem a maioria dos gateways) é serializada em JSON e
criptografada com SecretCipher antes de ir pro banco — mesmo padrão já
usado pra senha de SMTP em CompanyEmailConfiguration.password_encrypted.
Editar a credencial sem preencher um campo mantém o valor já salvo (não
sobrescreve com vazio), mesmo comportamento do formulário de e-mail.

Tela nova em painel/plataforma/empresas/<id>/gateway/, só Superadmin,
com link "Gateway →" ao lado de "Financeiro →" na tabela de empresas.

Nenhuma chamada real a gateway acontece a partir daqui — isso é só
armazenamento e gestão de credencial. A integração de verdade (gerar
boleto/PIX cobrável, confirmar pagamento) continua fora de escopo, mesma
decisão já tomada na v0.74.0 pros campos gateway_provider/
gateway_charge_id da fatura — evita ter que redesenhar o schema de
novo quando isso entrar.

Verificação feita

  • python -m py_compile em todos os arquivos Python tocados/novos.
  • Migration escrita à mão (sem GDAL neste ambiente de preparação),
    revisada campo a campo contra models.py.
  • Geração de slug (slugify + sufixo numérico em colisão) — validei a
    lógica do laço de sufixo com um script Python direto: nome único,
    colisão simples, colisão dupla, nome vazio — 4 asserções, todas
    passaram.
  • Chaves do static/css/app.css balanceadas (278/278).
  • {% if %}/{% endif %}/{% for %}/{% endfor %}/{% block %}/
    {% endblock %} balanceados em todos os templates tocados e novos.
  • Revisão manual de cada view de financeiro confirmando que a resolução
    de empresa do usuário comum nunca lê a query string (request.GET) —
    só o superusuário tem esse caminho, evitando qualquer brecha de
    autorização cruzada entre empresas.

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
(apps.billing.0002_gateway_configuration), roda automaticamente.
Depois, um Ctrl+F5 no navegador.

Teste sugerido: como Superadmin, cadastrar uma empresa nova pela Visão
da plataforma definindo tipo e nível de acesso do responsável; logar
como esse usuário e confirmar que o financeiro da própria empresa
aparece; criar um segundo usuário VIEW na mesma empresa e confirmar que
/painel/financeiro/ bloqueia ele; como Superadmin, acessar o
financeiro de qualquer empresa pela Visão da plataforma e salvar uma
credencial de gateway de teste.