There is a time when every SaaS need to get his money, and maybe you choose to get them month by month.
This is a post about the steps that I took to integrate Paypal recurring payments, and the problems that I run into.
The most common and known library for payment, and the one I was using for instant payment with Paypal is the ActiveMerchant gem, an huge container of all the payment gateway of the galaxy.
The gem is great, until you realize that you need recurring payments….
Some users provided forks with their own implementatios, but there wans’t a clean solution, and some messy code inside a huge library for me was not the way to go.
My Choice:
gem "paypal-recurring", "~> 1.1.0"
Before the integration of the gem is important to understand what we are going to do and why.
I attach an image from the Paypal developer website, that explain all the steps needed for a recurring payment:
WARN: The files in this section are only examples, the code miss some basic security, that can be easly added when integrated in your project.
Using the examples provided by the gem, and a little help from a recent Railscasts I ended up with this integration.
Subscription model: here you can manage the relations with the customers. One customer has many subscriptions, and a subscription belongs to a plan.
class Subscription
Through the paypal method we can access the PaypalPayment model, that manage the code between the gem “paypal-recurring” and our code.
The PaypalPayment module is as follow:
class PaypalPayment
def initialize(subscription)
@subscription = subscription
end
def checkout_details
process :checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
payment = process(:request_payment)
if payment.approved? && payment.completed?
# Set the subscription as paid
end
recurring = process(:create_recurring_profile, {period: :monthly, frequency: 1, start_at: Time.zone.now + 30.days})
@subscription.update_attribute(:paypal_profile_id, recurring.profile_id)
end
def cancel_recurring
ppr = PayPal::Recurring.new(:profile_id => @subscription.paypal_profile_id)
ppr.cancel
end
private
def process(action, options = {})
options = options.reverse_merge(
token: @subscription.paypal_token,
payer_id: @subscription.paypal_payer_id,
description: @subscription.name,
amount: @subscription.amount,
currency: "USD",
ipn_url: "http://www.example.com" + "/paypal/notifications/#{@subscription.id}"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
Checkout details: return some details about the customer that is subscribing to our website, like name and email address.
Checkout url: return the url of paypal where we need to redirect the customer to give us the permission to create a recurring payment.
Make recurring: Create an instant payment, and a recurring profile. Note: The first month is paid with the instant payment, so the recurring start from the next month.
Cancel recurring: Cancel the recurring profile
Everything is glued in the controller
class PaymentsController :notification
before_filter :load_subscription
def checkout
redirect_to @subscription.paypal.checkout_url(
return_url: "http://www.example.com" + "/paypal/review/#{@subscription.id}",
cancel_url: "http://www.example.com" + "/paypal/cancel/#{@subscription.id}"
)
end
def review
@subscription.update_attributes(paypal_token: params["token"], paypal_payer_id: params["PayerID"])
end
def complete
@subscription.paypal.make_recurring
end
def cancel
end
# Manage the paypal IPN
#
def notification
notify = PaypalNotification.new(request.raw_post)
if notify.acknowledge
begin
if notify.complete? && @subscription.amount == notify.amount
# Mark as paid
else
# Mark as error and investigate
end
rescue => e
# Mark as error and investigate
raise
end
end
render :nothing => true
end
private
def load_subscription
@subscription = Subscription.find(params[:id])
end
end
This steps should be enough to integrate paypal into your app. Paypal also provide a sandbox in wich you can create fake account and test that everything is working as expected.
Payment is mostly done in Paypal and model code, the views can be styled to reflect your website aspect and don’t require specific code.
On another post I will show how to manage the IPN with a custom library.
The code in this post can be found in this Gist: https://gist.github.com/4197985
Design by Simon Fletcher. Powered by Tumblr.
© Copyright 2010