Aula 92 – Django – Ecommerce – Cliente Stripe

Aula 92 – Ecommerce – Cliente Stripe

Loja Online - Django

Loja Online – Django

Voltar para página principal do blog

Todas as aulas desse curso

Aula 91                                   Aula 93

Redes Sociais:

facebook

 

Conecte-se comigo!

LinkedIn: Fique à vontade para me adicionar no LinkedIn.

Ao conectar-se comigo, você terá acesso a atualizações regulares sobre desenvolvimento web, insights profissionais e oportunidades de networking no setor de tecnologia.

GitHub: Siga-me no GitHub para ficar por dentro dos meus projetos mais recentes, colaborar em código aberto ou simplesmente explorar os repositórios que eu contribuo, o que pode ajudar você a aprender mais sobre programação e desenvolvimento de software.

Recursos e Afiliados

Explorando os recursos abaixo, você ajuda a apoiar nosso site.

Somos parceiros afiliados das seguintes plataformas:

  • Hostinger – Hospedagem web acessível e confiável.
  • Digital Ocean – Infraestrutura de nuvem para desenvolvedores.
  • One.com – Soluções simples e poderosas para o seu site.

Código da aula: Github

Educação e Networking

Amplie suas habilidades e sua rede participando de cursos gratuitos e comunidades de desenvolvedores:

Canais do Youtube

Explore nossos canais no YouTube para uma variedade de conteúdos educativos e de entretenimento, cada um com um foco único para enriquecer sua experiência de aprendizado e lazer.

Toti

Toti: Meu canal pessoal, onde posto clips artesanais de músicas que curto tocar, dicas de teoria musical, entre outras coisas.

Lofi Music Zone Beats

Lofi Music Zone Beats: O melhor da música Lofi para estudo, trabalho e relaxamento, criando o ambiente perfeito para sua concentração.

Backing Track / Play-Along

Backing Track / Play-Along: Acompanhe faixas instrumentais para prática musical, ideal para músicos que desejam aprimorar suas habilidades.

Código Fluente

Código Fluente: Aulas gratuitas de programação, devops, IA, entre outras coisas.

Putz!

Putz!: Canal da banda Putz!, uma banda virtual, criada durante a pandemia com mais 3 amigos, Fábio, Tatá e Lula.

Vocal Techniques and Exercises

Vocal Techniques and Exercises: Melhore suas técnicas vocais com exercícios práticos e dicas de especialistas em canto.

PIX para doações

PIX Nubank

PIX Nubank


 

Aula 92 – Ecommerce – Cliente Stripe

Temos dois lugares distintos para gerenciar aspectos ligados aos clientes: um é o nosso evento web, e o outro, diretamente no Stripe.

No caso desse projeto, o stripe irá armazenar os dados de nossos clientes, o que é ótimo, é o que queremos, terceirizar a preocupação com dados sensíveis, como dados do cartão de crédito.

Então, quando criarmos um novo BillingProfile no modelo Django, vamos focar inicialmente em estabelecer um registro básico que possa ser associado a um cliente no Stripe.

A ação primária realizada é a criação de um registro de cliente sem adicionar informações de pagamento, como números de cartão de crédito ou outros métodos de pagamento.

Isso é para simplificar o processo inicial de criação e garantir que dados sensíveis não sejam manuseados diretamente por nosso sistema, mas sim pelo Stripe, que é especializado e certificado para tal gestão segura.

Importância da Simplicidade e Segurança

A decisão de não adicionar descrições detalhadas ou métodos de pagamento diretamente no momento da criação do perfil de cobrança reflete uma prática de design que prioriza a simplicidade e a segurança.

Em vez de complicar o modelo inicial com múltiplos campos e responsabilidades, escolhemos delegar a gestão de informações críticas para uma plataforma confiável como o Stripe.

Isso reduz nossa carga de conformidade com padrões de segurança de dados, como PCI DSS (Padrão de Segurança de Dados para a Indústria de Cartões de Pagamento), e foca nosso sistema no gerenciamento de funcionalidades específicas do usuário e do negócio.

Coleta de E-mails e Comunicação Futura

Um dos únicos dados adicionais que consideramos coletar no momento da criação do perfil é o e-mail do cliente.

Isso não só facilita a comunicação futura, como também é necessário para a integração com o Stripe.

O e-mail torna-se um identificador fundamental para associar o perfil de cobrança no nosso sistema ao cliente no Stripe, permitindo transações futuras e a gestão de cobrança sem armazenar dados de pagamento diretamente.

Evento pre_save e Criação de Customer no Stripe

O uso do evento pre_save no Django é estratégico, pois permite a execução de lógicas importantes antes de salvar efetivamente o objeto no banco de dados.

No caso do BillingProfile, utilizamos esse gatilho para verificar se um customer_id já existe.

Se não existir e tivermos um e-mail válido, fazemos uma chamada à API do Stripe para criar um novo cliente e recebemos de volta um customer_id, que é então salvo no nosso modelo.

Essa abordagem garante que todos os perfis de cobrança tenham um identificador único no Stripe antes de serem salvos no nosso sistema.

Flexibilidade e Segurança na Gestão de Clientes

Esse método oferece uma flexibilidade considerável, especialmente quando surgem necessidades de alterar ou excluir informações de um cliente.

Em tais casos, podemos remover ou modificar os dados no Stripe e no nosso sistema simultaneamente, mantendo a sincronia entre as plataformas e garantindo que a segurança e a integridade dos dados do cliente sejam preservadas.

Então, se em algum momento precisarmos alterar ou excluir as informações de um cliente (por exemplo, se um cliente solicitar a exclusão de sua conta ou precisarmos atualizar seus dados), o sistema está configurado para lidar com essas alterações tanto localmente (em nosso banco de dados) quanto remotamente (no Stripe).

Quando fazemos uma alteração no nosso sistema, como excluir um perfil de cobrança ou atualizar um endereço de e-mail, essas alterações são refletidas simultaneamente no Stripe.

Isso é importante porque:

  1. Consistência de Dados: Garante que os dados do cliente estejam consistentes entre o nosso sistema e o Stripe. Por exemplo, se alterarmos o e-mail do cliente em nosso sistema, essa alteração também deve ser feita no Stripe para garantir que todas as comunicações e transações futuras usem a informação correta.
  2. Segurança de Dados: Ao manter os dados sincronizados e atualizados, reduzimos o risco de vazamentos de informações desatualizadas ou incorretas. Também ajuda a proteger a privacidade do cliente, assegurando que todas as informações armazenadas estejam corretas e apenas acessíveis quando necessário.

Portanto, o sistema atualmente não lida diretamente com métodos de pagamento ou detalhes complexos no momento da criação do perfil de cobrança, ele estabelece uma base sólida para operações seguras e eficientes, respeitando as melhores práticas de segurança de dados e facilitando a escalabilidade e a manutenção do sistema de e-commerce.

Partiu Código!

Abra models do billing e importe o Stripe, use o environ para pegar a chave do Stripe no arquivo .env, crie o campo
customer_id que será o identificador único do cliente no Stripe.

e_commerce/billing/models.py 


import environ
import stripe
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save, pre_save

from accounts.models import GuestEmail

User = settings.AUTH_USER_MODEL
# fulano@mail.com -> pode ter 1.000.000.000 billing profiles
# user fulano@mail.com -> pode ter apenas 1 billing profile
# Initialise environment variables
env = environ.Env()
environ.Env.read_env()
stripe.api_key = env('STRIPE_API_KEY')

class BillingProfileManager(models.Manager):
    def new_or_get(self, request):
        user = request.user
        guest_email_id = request.session.get('guest_email_id')
        created = False
        obj = None
        if user.is_authenticated:
            'logged in user checkout; remember payment stuff'
            obj, created = self.model.objects.get_or_create(
                            user=user, email=user.email)
        elif guest_email_id is not None:
            'guest user checkout; auto reloads payment stuff'
            guest_email_obj = GuestEmail.objects.get(id=guest_email_id)
            obj, created = self.model.objects.get_or_create(
                                            email=guest_email_obj.email)
        else:
            pass
        return obj, created

class BillingProfile(models.Model):
    user = models.OneToOneField(User, null = True, blank = True, on_delete = models.CASCADE)
    email = models.EmailField()
    active =    models.BooleanField(default = True)
    update = models.DateTimeField(auto_now = True)
    timestamp   = models.DateTimeField(auto_now_add = True)
    customer_id = models.CharField(max_length = 120, null = True, blank = True)
    # customer_id no Stripe ou Braintree ou ...
    objects = BillingProfileManager()
    def __str__(self):
        return self.email
def billing_profile_created_receiver(sender, instance, *args, **kwargs):
    if not instance.customer_id and instance.email:
        print("ACTUAL API REQUEST Send to stripe/braintree")
        customer = stripe.Customer.create(
                email = instance.email
            )
        print(customer)
        instance.customer_id = customer.id

pre_save.connect(billing_profile_created_receiver, sender=BillingProfile)

def user_created_receiver(sender, instance, created, *args, **kwargs):
    if created and instance.email:
        BillingProfile.objects.get_or_create(user = instance, email = instance.email)

post_save.connect(user_created_receiver, sender = User)

No código acima, o sinal pre_save, que é disparado antes do modelo ser salvo no banco de dados.

Detalhando cada parte

Função billing_profile_created_receiver

  • Definição da Função: billing_profile_created_receiver é uma função que será chamada automaticamente quando o sinal pre_save for disparado para o modelo BillingProfile. Ela atua como um receptor (receiver) para este sinal.
  • Parâmetros da Função:
    • sender: O modelo que enviou o sinal. Neste caso, é o modelo BillingProfile.
    • instance: A instância específica do modelo que está prestes a ser salva. Esse é o objeto BillingProfile que está sendo criado ou atualizado.
    • *args e **kwargs: Argumentos e palavras-chave argumentos adicionais que podem ser passados ao sinal, mas não são usados diretamente aqui.
  • Lógica da Função:
    • A função verifica primeiro se a instância do BillingProfile não tem um customer_id associado a ela e se possui um endereço de email válido (instance.email).
    • Se essas condições forem verdadeiras, isso indica que precisamos criar um novo cliente no Stripe (ou Braintree, mas o exemplo foca no Stripe) usando o email do perfil de cobrança.
    • Utiliza a API do Stripe para criar um novo cliente (stripe.Customer.create(email=instance.email)) e imprime a resposta (o objeto do cliente recém-criado) no console.
    • Atribui o id do cliente recém-criado do Stripe ao campo customer_id da instância do BillingProfile, preparando-o para ser salvo no banco de dados.

Conexão com o Sinal pre_save

  • Conexão do Sinal: pre_save.connect(billing_profile_created_receiver, sender=BillingProfile) conecta a função billing_profile_created_receiverao sinalpre_save para o modelo BillingProfile.
  • Isso significa que toda vez que um objeto BillingProfile estiver prestes a ser salvo, o Django automaticamente chamará billing_profile_created_receiver, permitindo que a lógica definida na função seja executada antes de efetivamente salvar o objeto no banco de dados.

django_ecommerce\e_commerce\e_commerce\settings.py 

"""
Django settings for e_commerce project.

Generated by 'django-admin startproject' using Django 2.1.4.

For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""

import os
import environ
import stripe

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Setup environment variables
env = environ.Env(DEBUG=(bool, False),)
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'xjmv-0^l__duq4-xp54m94bsf02lx4&1xka_ykd_(7(5#9^1o^'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[])
# Stripe Configuration
stripe.api_key = env('STRIPE_API_KEY')

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    #our apps
    'addresses',
    'analytics',
    'billing',
    'accounts',
    'carts',
    'orders',
    'products',
    'search',
    'tags',
]

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

AUTH_USER_MODEL = 'accounts.User' # changes the built-in user model to ours
FORCE_SESSION_TO_ONE = False
FORCE_INACTIVE_USER_ENDSESSION= False

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

LOGOUT_REDIRECT_URL = '/login/'
ROOT_URLCONF = 'e_commerce.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'e_commerce.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
     os.path.join(BASE_DIR, "static_local")
]

STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "static_root")

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "media_root")

Como criamos um novo campo no models, precisamos agora, executar minhas migrações.

python manage.py makemigrations

Agora o migrate.

python manage.py migrate

Testando e Verificando o Perfil de Cobrança

Após configurar a integração com o Stripe e implementar os mecanismos de criação de perfis de cobrança em nosso sistema, é essencial testar e verificar se tudo está funcionando conforme o esperado.

  1. Acesso ao Painel de Administração:
    • Inicie acessando o painel de administração do Django em localhost:8000/admin. Faça o login com suas credenciais de administrador para acessar as interfaces de gestão do sistema.
  2. Gerenciamento de Perfis de Cobrança:
    • Dentro do painel, navegue até a seção ‘Billing‘ e clique em ‘Billing profiles‘. Escolha um perfil de cobrança existente ou crie um novo. Ao salvar as alterações (clicando em ‘save and continue‘), o sistema tentará associar este perfil com um customer_id do Stripe.
  3. Verificação do Customer ID:
    • Se a integração estiver correta, o customer_id fornecido pelo Stripe será exibido no campo correspondente do perfil de cobrança. Isso indica que o perfil foi registrado no Stripe com sucesso.
  4. Console do Servidor:
    • Observe a saída no console do servidor para verificar os logs e a resposta retornada pelo Stripe. Isso ajudará a entender como as requisições estão sendo processadas e se há erros ou advertências a serem tratados.

Vantagens do Evento pre_save

O uso do evento pre_save traz várias vantagens estratégicas para o sistema:

  • Flexibilidade Operacional: Permite modificar ou validar dados antes de serem salvos no banco de dados. Isso é útil para garantir que todas as informações estejam corretas e completas.
  • Criação de Múltiplas Instâncias: Facilita a criação de múltiplos registros simultaneamente, se necessário, garantindo que todos passem pelos mesmos processos de validação e ajuste.
  • Gerenciamento Proativo de Dados: Em caso de problemas ou requisições de exclusão de dados por parte de clientes, é possível remover as informações de forma sincronizada no nosso sistema e no Stripe, garantindo a conformidade com normas de proteção de dados e privacidade.

Aplicabilidade Independente da Autenticação

  • Usuários Autenticados e Não Autenticados: O sistema está desenhado para tratar perfis de cobrança tanto de usuários autenticados quanto de visitantes (não autenticados). Isso assegura que a experiência do usuário seja consistente e segura, independentemente do seu status de login.

Próximos Passos: Realizando Transações

  • Associação de Métodos de Pagamento: Antes de realizar uma transação, é crucial associar um método de pagamento válido, como um cartão de crédito, ao perfil do usuário. Isso prepara o sistema para processar pagamentos e realizar transações de forma segura e eficiente.

Por essa aula é só!

Voltar para página principal do blog

Todas as aulas desse curso

Aula 91                                   Aula 93

Nos vemos na próxima então, \o/  😉 Bons Estudos!

About The Author
-

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>