Skip to content
Lessa edited this page Sep 22, 2025 · 9 revisions

Configuração do Stripe no Django

Documentação de referência: dj-stripe API Keys / Stripe: Build a subscription integration

Configuração das chaves API:

  1. Acesse a área de API Keys no Stripe
  2. Insira o token de acesso privado da conta
  3. Execute no container da aplicação:
python manage.py djstripe_sync_models

Este comando sincroniza os modelos do Stripe com a aplicação Django.

⚠️ A sincronização interage diretamente com os dados do Stripe. Tenha cuidado ao modificar ou excluir campos, pois as alterações podem ser irreversíveis.

Documentação da Integração com Stripe

Este documento detalha a integração do backend com o sistema de pagamentos Stripe, cobrindo a configuração, as operações da API GraphQL e o manuseio de webhooks.

1. Configuração

A configuração do Stripe é gerenciada por variáveis de ambiente e difere entre os ambientes de desenvolvimento (local.py) e produção (remote.py).

Variáveis de Ambiente

As seguintes variáveis de ambiente são necessárias para a integração:

  • STRIPE_LIVE_MODE: Define se a API do Stripe operará em modo "live" (produção) ou "test". (Ex: True ou False).
  • STRIPE_LIVE_SECRET_KEY: Chave secreta da API do Stripe para o modo "live".
  • STRIPE_TEST_SECRET_KEY: Chave secreta da API do Stripe para o modo "test".
  • DJSTRIPE_WEBHOOK_SECRET: Chave secreta para validar os webhooks recebidos do Stripe, garantindo que eles são autênticos.

Nota: Para que a integração, especialmente os webhooks, funcione como esperado, o backend precisa estar em um ambiente online acessível pelo Stripe. Localmente, mesmo com as variáveis preenchidas, os eventos de webhook não serão recebidos.

Arquivos de Configuração (settings)

Em backend/settings/local.py e backend/settings/remote.py, o dj-stripe é configurado da seguinte forma:

# Stripe
def as_bool(var):
    if isinstance(var, str):
        if var.lower() in ["true", "t", "1"]:
            return True
    return False

STRIPE_LIVE_MODE = as_bool(getenv("STRIPE_LIVE_MODE"))
STRIPE_LIVE_SECRET_KEY = getenv("STRIPE_LIVE_SECRET_KEY")
STRIPE_TEST_SECRET_KEY = getenv("STRIPE_TEST_SECRET_KEY")
DJSTRIPE_WEBHOOK_SECRET = getenv("DJSTRIPE_WEBHOOK_SECRET")
DJSTRIPE_USE_NATIVE_JSONFIELD = True
DJSTRIPE_FOREIGN_KEY_TO_FIELD = "id"

A chave da API (stripe.api_key) é definida dinamicamente em backend/apps/account_payment/graphql.py com base no STRIPE_LIVE_MODE.

if settings.STRIPE_LIVE_MODE:
    stripe.api_key = settings.STRIPE_LIVE_SECRET_KEY
else:
    stripe.api_key = settings.STRIPE_TEST_SECRET_KEY

2. API GraphQL (account_payment/graphql.py)

A interação do frontend com o Stripe é feita através de mutações e queries GraphQL. Todas as mutações que envolvem dados sensíveis ou ações de usuário exigem autenticação (@login_required).

Queries

  • allStripePrice: Retorna uma lista de todos os planos (preços) disponíveis no Stripe. Permite filtrar por id e active.

Mutações

Gerenciamento de Clientes (Customer)

  • createStripeCustomer: Cria um cliente (customer) no Stripe associado a uma conta de usuário (Account) no sistema. Se o cliente já existir, a operação é ignorada.
  • updateStripeCustomer: Atualiza os dados de um cliente no Stripe, como nome, e-mail e endereço.

Gerenciamento de Assinaturas (Subscription)

  • createStripeSubscription: Cria uma nova assinatura para um usuário.

    • Se for a primeira assinatura do usuário, um SetupIntent é criado para configurar o método de pagamento com um trial de 7 dias.
    • Se não for a primeira, uma assinatura normal é criada, retornando um client_secret para o frontend finalizar o pagamento.
    • Suporta a aplicação de cupons de desconto.
  • deleteStripeSubscription: Agenda o cancelamento de uma assinatura ao final do período de faturamento (at_period_end=True).

Gerenciamento de Membros da Assinatura

  • addStripeSubscriptionMember: Adiciona um usuário existente na plataforma a uma assinatura "Pro" existente. O usuário adicionado passa a ter os benefícios do plano.
  • removeStripeSubscriptionMember: Remove um usuário de uma assinatura. O nome update é um pouco enganoso; a ação real é de remoção.
  • removeAllStripeSubscriptionMembers: Remove todos os membros de uma assinatura, exceto o administrador.

Outras Mutações

  • validateStripeCoupon: Verifica se um cupom de desconto é válido para um plano específico.

    • Lógica de Funcionamento:

      1. O Stripe diferencia Coupon (a regra de desconto, ex: "10% OFF") do Promotion Code (o código que o cliente usa, ex: "PROMO10").
      2. A mutação recebe o Promotion Code e busca por ele no Stripe.
      3. Se o Promotion Code for encontrado e estiver ativo, o sistema busca o Coupon associado a ele.
      4. Verifica se o Coupon também é válido (não expirou).
      5. Busca o preço do plano (price_id) no banco de dados local para calcular o valor do desconto (se for percentual).
      6. Calcula o valor final do desconto (seja ele fixo ou percentual).
      7. Retorna um objeto indicando se o cupom é is_valid, o valor do desconto (discount_amount) e sua duração (duration e duration_in_months).
    • Aplicação do Cupom:

      • Se a validação for bem-sucedida, o Promotion Code (o código original do cupom) pode ser passado para a mutação createStripeSubscription no campo coupon. O Stripe se encarrega de aplicar o desconto na assinatura.
  • validateStripeCoupon: Verifica se um cupom de desconto é válido e retorna detalhes como o valor do desconto e a duração.

  • changeUserGcpEmail: Altera o e-mail do Google Cloud (GCP) de um usuário. Se o usuário tiver uma assinatura ativa, o e-mail antigo é removido do grupo do Google e o novo é adicionado.

3. Webhooks (account_payment/webhooks.py)

Os webhooks são o mecanismo pelo qual o Stripe notifica o backend sobre eventos que ocorrem de forma assíncrona (ex: pagamento confirmado, falha na renovação, etc.). O dj-stripe facilita o recebimento e processamento desses eventos.

Nota Importante: Os ambientes de development (local) e staging (homologação) compartilham a mesma configuração de webhooks do Stripe no modo de teste. Isso significa que, ao atualizar ou testar um webhook, a alteração impactará ambos os ambientes. É necessário coordenar as atualizações para evitar interrupções.

Funções Auxiliares

  • add_user(email): Adiciona um usuário a um grupo específico no Google Workspace. Isso é usado para conceder acesso a recursos "Pro".
  • remove_user(email): Remove um usuário do grupo do Google Workspace, revogando o acesso.
  • get_subscription(event): Localiza ou cria uma representação interna da assinatura (Subscription) com base no evento recebido do Stripe.

Handlers de Eventos

Cada evento do Stripe é tratado por uma função específica decorada com @webhooks.handler("event.name").

  • customer.updated: Se o e-mail de um cliente for alterado no portal do Stripe, este evento atualiza o e-mail na conta de usuário (Account) correspondente no banco de dados.

  • customer.subscription.created e customer.subscription.updated:

    • Manipulados pela função handle_subscription.
    • Se o status da assinatura for active ou trialing, a assinatura interna é marcada como ativa e o usuário é adicionado ao grupo do Google.
    • Para outros status (ex: canceled, unpaid), a assinatura é marcada como inativa e o usuário é removido do grupo.
  • customer.subscription.deleted:

    • Marca a assinatura interna como inativa.
    • Remove o usuário do grupo do Google.
  • customer.subscription.paused:

    • Marca a assinatura interna como inativa.
    • Remove o usuário do grupo do Google.
  • customer.subscription.resumed:

    • Marca a assinatura interna como ativa.
    • Adiciona o usuário de volta ao grupo do Google.
  • setup_intent.succeeded:

    • Ocorre após o usuário configurar um método de pagamento pela primeira vez (durante o trial).
    • Define o método de pagamento como padrão para o cliente no Stripe.
    • Cria a assinatura com um período de trial de 7 dias.

4. Fluxo de Vida do Usuário "Pro"

  1. Cadastro e Login: O usuário se cadastra na plataforma.
  2. Escolha do Plano: O usuário seleciona um plano "Pro" no frontend.
  3. Criação da Assinatura:
    • O frontend chama a mutação createStripeSubscription.
    • Como é a primeira vez, o backend cria um SetupIntent no Stripe e retorna o client_secret.
    • O frontend usa o client_secret para exibir o formulário de cartão de crédito do Stripe Elements.
  4. Configuração do Pagamento:
    • O usuário preenche os dados do cartão.
    • O Stripe envia o webhook setup_intent.succeeded.
  5. Início do Trial:
    • O handler setup_intent_succeeded recebe o webhook.
    • Ele cria a assinatura no Stripe com 7 dias de trial.
    • O Stripe, por sua vez, envia o webhook customer.subscription.created com status trialing.
  6. Concessão de Acesso:
    • O handler subscribe (via handle_subscription) recebe o evento.
    • A assinatura interna é marcada como ativa.
    • A função add_user é chamada para adicionar o e-mail do usuário ao grupo do Google, liberando o acesso "Pro".
  7. Fim do Trial e Primeiro Pagamento: Após 7 dias, o Stripe tenta cobrar o valor do plano. Se for bem-sucedido, a assinatura passa para o status active. Se falhar, passa para past_due ou unpaid.
  8. Cancelamento:
    • O usuário solicita o cancelamento no frontend.
    • A mutação deleteStripeSubscription é chamada, cancelando a renovação automática no Stripe.
    • Ao final do período pago, o Stripe envia o webhook customer.subscription.deleted.
  9. Revogação do Acesso:
    • O handler unsubscribe recebe o evento.
    • A assinatura interna é marcada como inativa.
    • A função remove_user é chamada, removendo o acesso "Pro" do usuário.

5. Testes (account_payment/tests.py)

Os testes para a integração com o Stripe estão localizados em backend/apps/account_payment/tests.py. Eles utilizam pytest e unittest.mock para simular chamadas à API do Stripe e ao dj-stripe, garantindo que as mutações GraphQL se comportem como esperado sem fazer chamadas reais à rede.

Exemplos de Testes:

  • test_all_stripe_price_call: Verifica se a query AllStripePrice retorna uma lista vazia quando não há preços no banco de dados de teste.
  • test_create_stripe_customer_call: Garante que, ao chamar a mutação CreateStripeCustomer, os métodos DJStripeCustomer.create e StripeCustomer.modify são chamados uma vez.
  • test_update_stripe_customer_call: Assegura que a mutação UpdateStripeCustomer chama o método StripeCustomer.modify para atualizar os dados do cliente.

Configuração de Webhooks:

  1. Após a sincronização, acesse Webhook endpoints no Stripe
  2. Crie um novo webhook para integrar o ambiente Django com o Stripe

Diagramas do fluxo do Stripe

Fluxo de Nova Assinatura (com Período de Teste)

sequenceDiagram
    participant Usuário
    participant Frontend
    participant Backend
    participant Stripe API
    participant Google Workspace

    Usuário->>Frontend: 1. Escolhe o plano "Pro"
    Frontend->>Backend: 2. Chama a mutação `createStripeSubscription`
    Backend->>Stripe API: 3. Cria um `SetupIntent` (pois é a 1ª assinatura)
    Stripe API-->>Backend: 4. Retorna o `client_secret` do SetupIntent
    Backend-->>Frontend: 5. Retorna o `client_secret`
    Frontend->>Usuário: 6. Exibe o formulário de cartão (Stripe Elements)
    Usuário->>Frontend: 7. Preenche os dados do cartão
    Frontend->>Stripe API: 8. Envia os dados do cartão para o Stripe
    
    Note over Stripe API: Stripe processa e armazena o método de pagamento.

    Stripe API-->>Backend: 9. Envia webhook: `setup_intent.succeeded`
    Backend->>Stripe API: 10. (No handler do webhook) Cria a assinatura com 7 dias de trial
    Stripe API-->>Backend: 11. Envia webhook: `customer.subscription.created` (status: `trialing`)
    
    Note over Backend: Handler `handle_subscription` é acionado.
    
    Backend->>Google Workspace: 12. Adiciona usuário ao grupo "Pro" (`add_user`)
    Google Workspace-->>Backend: Confirmação
    Backend-->>Usuário: Acesso "Pro" liberado
Loading

Fluxo de Assinatura (Sem Período de Teste)

sequenceDiagram
    participant Usuário
    participant Frontend
    participant Backend
    participant Stripe API
    participant Google Workspace

    Usuário->>Frontend: 1. Escolhe o plano "Pro"
    Frontend->>Backend: 2. Chama a mutação `createStripeSubscription`
    
    Note over Backend: Backend verifica que o usuário não tem direito a trial.

    Backend->>Stripe API: 3. Cria uma assinatura com `payment_behavior="default_incomplete"`
    Stripe API-->>Backend: 4. Retorna o objeto da assinatura, incluindo o `client_secret` do `PaymentIntent` da primeira fatura
    Backend-->>Frontend: 5. Retorna o `client_secret`
    
    Frontend->>Usuário: 6. Exibe o formulário de cartão (Stripe Elements) para pagamento
    Usuário->>Frontend: 7. Preenche os dados e confirma o pagamento
    Frontend->>Stripe API: 8. Envia os dados para o Stripe confirmar o pagamento
    
    Note over Stripe API: Stripe processa o pagamento.

    Stripe API-->>Backend: 9. Envia webhook: `customer.subscription.created` (status: `active`)
    
    Note over Backend: Handler `handle_subscription` é acionado.
    
    Backend->>Google Workspace: 10. Adiciona usuário ao grupo "Pro" (`add_user`)
    Google Workspace-->>Backend: Confirmação
    Backend-->>Usuário: Acesso "Pro" liberado
Loading

Fluxo de Cancelamento de Assinatura

sequenceDiagram
    participant Usuário
    participant Frontend
    participant Backend
    participant Stripe API
    participant Google Workspace

    Usuário->>Frontend: 1. Solicita o cancelamento da assinatura
    Frontend->>Backend: 2. Chama a mutação `deleteStripeSubscription`
    Backend->>Stripe API: 3. Agenda o cancelamento no final do período (`cancel_at_period_end=true`)
    Stripe API-->>Backend: Confirmação
    Backend-->>Frontend: 4. Confirma que o cancelamento foi agendado
    
    Note over Stripe API: O tempo passa...
    Note over Stripe API: Fim do período de faturamento chega.

    Stripe API-->>Backend: 5. Envia webhook: `customer.subscription.deleted`
    
    Note over Backend: Handler `unsubscribe` é acionado.

    Backend->>Google Workspace: 6. Remove usuário do grupo "Pro" (`remove_user`)
    Google Workspace-->>Backend: Confirmação
    Backend-->>Usuário: Acesso "Pro" revogado
Loading

Fluxo de Adição de Membro à Assinatura

sequenceDiagram
    participant Admin
    participant Frontend
    participant Backend
    participant Google Workspace

    Admin->>Frontend: 1. Adiciona e-mail do novo membro
    Frontend->>Backend: 2. Chama a mutação `addStripeSubscriptionMember`
    
    Note over Backend: Valida se o Admin é dono da assinatura.

    Backend->>Google Workspace: 3. Adiciona novo membro ao grupo "Pro" (`add_user`)
    Google Workspace-->>Backend: Confirmação
    Backend-->>Frontend: 4. Retorna sucesso (ok: true)
    Frontend-->>Admin: 5. Confirma que o membro foi adicionado
Loading
Clone this wiki locally