Fork me on GitHub

Samuel Simões

Usando PayPal IPN com Pagamentos recorrentes

12/05/2013

Edit: você pode ler um guia mais completo de como criar uma estrutura de pagamentos recorrentes com Rails e PayPal clicando aqui!

O PayPal IPN, para os que não sabem, é o sistema de notificação instantânea que o PayPal oferece cujo o objetivo é retornar em uma URL do seu aplicativo um request POST contendo informações referentes a alguma ação ocorrida em alguma das suas transações. Exemplo: um usuário cancela um pagamento recorrente, logo após o usuário tomar essa ação, na URL configurada anteriormente, você irá receber o POST com as informações da ação.

Não vou entrar no mérito de explicar todo o funcionamento dos pagamentos recorrentes, mas caso você esteja usando Ruby você pode usar a ótima paypal-recurring gem e recomendo também você ver a palestra do Nando Vieira sobre pagamentos recorrentes com PayPal e a paypal-recurring gem na Guru-SP e o episódio #289 do Rails Casts (PayPal Recurring Billing).

Para você conseguir testar a recepção de notificações no seu ambiente de desenvolvimento, que provavelmente está rodando localmente, você deve expor o acesso ao seu app para que ele fique acessível ao PayPal, para essa tarefa eu recomendo o uso do localtunnel.

Para pagamentos do tipo express checkout você pode definir na criação da transação qual vai ser a URL que vai receber as IPNs para aquele pedido, mas infelizmente essa definição dinâmica parece não funcionar para pagamentos recorrentes.

ppr = PayPal::Recurring.new({
  # Não funciona para pagamentos recorrentes :(
  :ipn_url	  => "http://example.com/paypal/ipn"
})

response = ppr.checkout
puts response.checkout_url if response.valid?

A solução é você definir qual vai ser a URL que vai receber as IPNs no site do PayPal (tanto produção quanto sandbox), no caso do cenário de desenvolvimento acesse a PayPal Developer Network e na conta BUSINESS clique em sandbox site.

Depois acesse: My Account > Profile > My Selling Tools.

Infelizmente o sandbox do PayPal é bastante lento e problemático, ao clicar no link deveria, no corpo da página, aparecer as devidas configurações, mas isso não acontece, o site fica carrega ad eternum.

A solução nesse caso é copiar o link que fica na sidebar esquerda (imagem acima), retirar o beta- da URL e acessar normalmente, exemplo:

https://www.beta-sandbox.paypal.com/cgi-bin/webscr?cmd=_profile-display-handler&tab_id=SELLER_PREFERENCES

vira:

https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_profile-display-handler&tab_id=SELLER_PREFERENCES

Feito isso você provavelmente estará tendo acesso a página de configurações de vendedor, nessa página você deve acessar o item Instant payment notifications ou algo em torno disso. O link provavelmente irá te levar para um erro 404, faça o processo de “corrigir” a URL novamente.

Na página de configuração defina a Notification URL apontando para uma URL pública do seu app que leve para onde você quer que suas IPNs sejam devidamente capturadas.

Um exemplo de action para capturar as notificações usando a própria classe de notificações não documentado da paypal-recurring gem seria mais ou menos isso:

routes.rb

App::Application.routes.draw do
  post 'paypal/ipn_listener' => 'paypal#ipn_listener'
end

paypal_controller.rb

class PaypalController < ApplicationController
  protect_from_forgery :except => [:ipn_listener]

  def ipn_listener
    notification = PayPal::Recurring::Notification.new(params)

    # Se é uma notificação de pagamento recorrente
    notification.recurring_payment?

    # Se é uma notificação sobre a criação do profile de recorrência
    notification.recurring_payment_profile?

    # ID do profile
    notification.payment_id

    # Status do Profile
    notification.profile_status

    # Referência previamente definida por você
    notification.reference

    render nothing: true
  end
end

Dê uma lida nessa classe, ela é super simples e bem esclarecedora.

Dúvidas? Deixe nos comentários. =D

Este post tem o "código aberto", caso encontre algo errado, desatualizado ou queira incorporar alguma coisa faça um pull request.

comments powered by Disqus

Samuel Simões ~ @samuelsimoes