Tutoriais
Habilitar pagamento com Stripe
Com esse tutorial você será capaz habilitar o pagamento das assinaturas do seu projeto com stripe.
Passo a Passo
JustLaunch utiliza Stripe como gateway de pagamento para cobrar assinatura. O template já vem todo configurado para utilização da stripe como gateway de pagamento e além de fazer todo o gerenciamento de estado da assinatura, ou seja automaticamente ficamos ouvindo os eventos da stripe para verificar se o usuário - assinou, cancelou, mudou de assinatura entre outras funcionalidade, só precisamos habilitar em nosso código, siga as instruções abaixo para habilitar a stripe como gateway de pagamento.
Crie uma conta no Stripe
Precisamos criar um conta no stripe para obter as credenciais necessárias para habilitar o gateway de pagamento. Crie uma conta no Stripe
Após a criação de uma conta no stripe você sera capaz de visualizar acessar a dashboard da stripe
Adicione no .ENV
Acesse o menu desenvolvedores e logo após o menu de API key
Adicione no seu .env em STRIPE_KEY a API key Chave secreta que está na stripe e mude para true a váriavel USE_STRIPE
USE_STRIPE=true
STRIPE_KEY= {Chave secreta}
Adicione Back-end no arquivo serverless.yml
STRIPE_API_KEY: {Chave secreta}
Configure o webhook na stripe
Acesse o menu desenvolvedores e logo após o menu de webhook
Clique em adicionar um novo endpoint e você será direcionado para tela abaixo
Após entrar escolha os eventos que seu webhook vai ficar escultando e escolha somente esses -> customer.subscription.created, customer.subscription.deleted, customer.subscription.pending_update_applied , customer.subscription.pending_update_expired, customer.subscription.resumed e customer.subscription.updated
E adicione a url do dominio do seu front-end + api/stripe/webhook, veja o exemplo abaixo
Se estiver utilizando back-end separado do front-end
Se você ainda não tem a url do Microsserviço de usuário, Acesse o tutorial de autenticação e vá para sessão extra para realizar o deploy do Microsserviço de usuário e obter a url do serviço.
Após configurar o webhook você terá acesso ao Segredo da assinatura clique em revelar
Após revelar o segredo da assinatura copie e adicione no arquivo .env.local do seu Front-end
STRIPE_WEBHOOK_SECRET: {Segredo da assinatura}
Se estiver utilizando back-end separado do front-end
Após revelar o segredo da assinatura copie e adicione no arquivo serverless.yml do Back-end
STRIPE_WEBHOOK_KEY: {Segredo da assinatura}
Criar o produto de assinaturas
Na nossa landing page temos a opção de colocar 2 assinaturas como podemos ver na imagem abaixo
Então na stripe vamos precisar criar 2 produtos um Starter e outro Pro
Modo Teste
Se você tiver utilizando o modo teste, quando você transferir para o modo produção na stripe deve recriar seus produtos no modo produção também.
Para criar esses produtos na stripe devemos clicar no menu chamado mais e entrar no painel Catálogo de produtos
Após entrar no Catálogo de produtos podemos criar o produto no modelo recorrente ou avulso
Clique em adicionar produto
Preencha as informações do seu produto, Escolha um preço, o Modelo recorrente (mensal ou anual) ou Avulso e o Nome tem que ser Starter ou Pro
Repita o mesmo procedimento para o outro nome de plano ou produto e ao final você terá como resultado dois produtos Starter e Pro
Se estiver utilizando back-end separado do front-end
Pule para Back-end(opcional) e siga as instruções e depois volte para seção front-end
Front-end
Vamos precisar adicionar a sessão do usuário na landing page para verificar se o usuário está logado para conseguir alterar o estado da assinatura dele para isso vamos adicionar o código abaixo e trocar outra linha de código.
As alterações estão com uma -> para você conseguir identificar o que precisa alterar na sua landing page para habilitar a sessão.
import Providers from '@/providers/Providers';
import {
CallToAction,
Faq,
Features,
Footer,
Header,
Hero,
Problems,
Stats,
Testimonials,
Pricing,
} from '../shared/@JustLaunch/components/LandingPage';
import { useLandingPageInternationalization } from '../shared/@JustLaunch/hooks/contents/useLandingPageInternationalization';
-> import { nextAuthOptions } from '../api/auth/[...nextauth]/auth';
-> import { getServerSession } from 'next-auth';
export default async function LandingPage() {
-> const session = await getServerSession(nextAuthOptions);
const {
headerIntl,
heroIntl,
problemsIntl,
footerIntl,
callToActionIntl,
statsIntl,
testimonialsIntl,
faqsIntl,
pricingIntl,
featuresIntl,
} = await useLandingPageInternationalization();
return (
<>
<Providers>
-> <Header intl={headerIntl} session={session} />
<Hero intl={heroIntl} />
<Problems intl={problemsIntl} />
<Features intl={featuresIntl} />
<Testimonials intl={testimonialsIntl} />
<Stats intl={statsIntl} />
<Pricing intl={pricingIntl} />
<Faq intl={faqsIntl} />
<CallToAction intl={callToActionIntl} />
<Footer intl={footerIntl} />
</Providers>
</>
);
}
Testar assinatura ou produto avulso com cartão de teste
Para confirmar que sua integração está funcionando corretamente, simule transações sem mover nenhum dinheiro usando valores especiais no modo de teste.
Os cartões de teste permitem simular vários cenários:
Pagamentos sucedidos por marca ou país do cartão Erros de cartão devidos a pagamentos recusados, fraudes ou dados inválidos Contestações e reembolsos Autenticação com 3D Secure e PINs
Confira os cartões de teste da stripe aqui.
Back-end (Opcional)
Vamos precisar retirar os comentários de algumas linhas então copie e cole o código abaixo no arquivo CreateUsersUseCase
import { IAuthService } from '@domain/contracts/infrastructures/IAuthService';
import { IPaymentGatewayService } from '@domain/contracts/infrastructures/IPaymentGatewayService';
import { IUsersRepository } from '@domain/contracts/infrastructures/IUsersRepository';
import { ICreateUsersUseCase } from '@domain/contracts/usecases/ICreateUsersUseCase';
import { RequestToCreateUsersDTO } from '@domain/dtos/RequestToCreateUsersDTO';
import { User } from '@domain/entities/User';
import { SubscriptionStatus } from '@domain/enums/SubscriptionStatus';
import { ApplicationResult, ApplicationResultSuccess } from '@kernelsoftware/shared';
import { ILogger } from '@kernelsoftware/shared/dist/domain/contracts/infrastructure/ILogger';
import { buildReferralId } from '@utils/buildReferralId';
import { inject, injectable } from 'inversify';
@injectable()
export class CreateUsersUseCase implements ICreateUsersUseCase {
className: string;
constructor(
@inject('Logger')
private logger: ILogger,
@inject('AuthService')
private authService: IAuthService,
@inject('PaymentGatewayService')
private paymentGatewayService: IPaymentGatewayService,
@inject('UsersRepository')
private usersRepository: IUsersRepository<User>
) {
this.className = 'CreateUsersUseCase';
}
async execute(data: RequestToCreateUsersDTO): Promise<ApplicationResult<User>> {
const context = `${this.className}.execute`;
this.logger.info('Start execute', {
email: data.email,
name: data.name,
context,
});
const authResult = await this.authService.signUp(data);
if (authResult.isError) {
this.logger.error('Error on execute - AuthService', authResult.errorMessage, {
context,
});
return authResult;
}
const uuid = User.generateId();
const paymentGatewayResult = await this.paymentGatewayService.createCustomer({
...data,
userId: uuid,
tenantId: authResult.data,
});
if (paymentGatewayResult.isError) {
this.logger.error('Error on execute - PaymentGatewayService', paymentGatewayResult.errorMessage, {
context,
});
await this.authService.deleteUser(authResult.data);
return paymentGatewayResult;
}
const userDomain = User.fromPlain(User, {
id: uuid,
email: data.email,
name: data.name,
phone: data.phone,
subscriptionStatus: SubscriptionStatus.PENDING,
tenantId: authResult.data,
referralId: buildReferralId(),
customerId: paymentGatewayResult.data,
});
const result = await this.usersRepository.upsert(userDomain);
if (result.isError) {
this.logger.error('Error on execute - AuthService', result.errorMessage, {
context,
});
await this.authService.deleteUser(authResult.data);
await this.paymentGatewayService.deleteCustomer(paymentGatewayResult.data);
return result;
}
this.logger.info('Successful execution', {
context,
});
return new ApplicationResultSuccess(result.data);
}
}