Aula 92 – Django – Ecommerce – Cliente Stripe
Aula 92 – Ecommerce – Cliente Stripe
Voltar para página principal do blog
Todas as aulas desse curso
Aula 91 Aula 93
Redes Sociais:
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:
- Digital Innovation One – Cursos gratuitos com certificado.
- Workover – Aprenda Python3 gratuitamente.
- Comunidades de desenvolvedores para networking:
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
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:
- 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.
- 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 sinalpre_save
for disparado para o modeloBillingProfile
. Ela atua como um receptor (receiver) para este sinal. - Parâmetros da Função:
sender
: O modelo que enviou o sinal. Neste caso, é o modeloBillingProfile
.instance
: A instância específica do modelo que está prestes a ser salva. Esse é o objetoBillingProfile
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 umcustomer_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 campocustomer_id
da instância doBillingProfile
, preparando-o para ser salvo no banco de dados.
- A função verifica primeiro se a instância do
Conexão com o Sinal pre_save
- Conexão do Sinal:
pre_save.connect(billing_profile_created_receiver, sender=BillingProfile)
conecta a funçãobilling_profile_created_receiver
ao sinalpre_save
para o modeloBillingProfile
. - 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.
- 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.
- Inicie acessando o painel de administração do Django em
- 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.
- 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
- 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.
- Se a integração estiver correta, o
- 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.