Skip to content

Instantly share code, notes, and snippets.

@dmitriy-kiriyenko
Created July 1, 2011 08:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dmitriy-kiriyenko/1058090 to your computer and use it in GitHub Desktop.
Save dmitriy-kiriyenko/1058090 to your computer and use it in GitHub Desktop.
Paypal Recurring Gateway, based on ActiveMerchant
class PaypalRecurringGateway < ActiveMerchant::Billing::PaypalGateway
NS2 = 'n2:'
self.default_currency = 'USD'
def create_recurring(money, credit_card, options = {})
request = create_recurring_request(money, credit_card, options)
commit("CreateRecurringPaymentsProfile", request)
end
def update_recurring(money, profile_id, options = {})
request = update_recurring_request(money, profile_id, options)
commit("UpdateRecurringPaymentsProfile", request)
end
def cancel_recurring(profile_id)
request = change_recurring_status_request(profile_id, :cancel)
commit('ManageRecurringPaymentsProfileStatus', request)
end
def inquiry_recurring(profile_id)
request = request_recurring_details(profile_id)
commit('GetRecurringPaymentsProfileDetails', request)
end
protected
def build_response(success, message, response = {}, options = {})
require 'active_merchant/billing/gateways/payflow/payflow_response'
ActiveMerchant::Billing::PayflowResponse.new(success, message, response, options)
end
private
def create_recurring_request(money, credit_card, options)
options.reverse_merge!(:auto_bill_outstanding_amount => false, :starting_at => Time.now, :periodicity => :monthly)
build_xml.tag!('CreateRecurringPaymentsProfileReq', 'xmlns' => PAYPAL_NAMESPACE) do |xml|
xml.tag!('CreateRecurringPaymentsProfileRequest', 'xmlns:n2' => EBAY_NAMESPACE) do |xml|
xml.tag!(NS2 + 'Version', API_VERSION)
xml.tag!(NS2 + 'CreateRecurringPaymentsProfileRequestDetails') do |xml|
add_credit_card(xml, credit_card, nil, options)
xml.tag!(NS2 + 'RecurringPaymentsProfileDetails') do |xml|
xml.tag!(NS2 + 'BillingStartDate', format_rp_date(options[:starting_at])) # Required
end
xml.tag!(NS2 + 'ScheduleDetails') do |xml|
xml.tag!(NS2 + 'Description', options[:description]) # Required
frequency, period = get_pay_period(options[:periodicity])
xml.tag!(NS2 + 'PaymentPeriod') do |xml|
xml.tag!(NS2 + 'BillingPeriod', period) # Required
xml.tag!(NS2 + 'BillingFrequency', frequency.to_s) # Required
xml.tag!(NS2 + 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)) # Required
xml.tag!(NS2 + 'TotalBillingCycles', options[:payments]) unless options[:payments].blank? # Optional
end
xml.tag!(NS2 + 'MaxFailedPayments', options[:max_failed_payments]) unless options[:max_failed_payments].blank? # Optional
xml.tag!(NS2 + 'AutoBillOutstandingAmount', options[:auto_bill_outstanding_amount] ? 'AddToNextBilling' : 'NoAutoBill') # Required
end
end
end
end
end
def update_recurring_request(money, profile_id, options)
build_xml.tag!('UpdateRecurringPaymentsProfileReq', 'xmlns' => PAYPAL_NAMESPACE) do |xml|
xml.tag!('UpdateRecurringPaymentsProfileRequest', 'xmlns:n2' => EBAY_NAMESPACE) do |xml|
xml.tag!(NS2 + 'Version', API_VERSION)
xml.tag!(NS2 + 'UpdateRecurringPaymentsProfileRequestDetails') do |xml|
xml.tag!(NS2 + 'ProfileID', profile_id) # Required
xml.tag!(NS2 + 'Note', options[:description]) unless options[:description].blank? # Optional
credit_card = options[:credit_card]
unless credit_card.blank? # Optional
add_credit_card(xml, credit_card, nil, options)
end
xml.tag!(NS2 + 'PaymentPeriod') do |xml|
xml.tag!(NS2 + 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money))
xml.tag!(NS2 + 'TotalBillingCycles', options[:payments]) unless options[:payments].blank? # Optional
end
end
end
end
end
def change_recurring_status_request(profile_id, new_status, options = {})
raise ArgumentError, 'Invalid Request: Missing Profile ID' if profile_id.blank?
raise ArgumentError, 'Invalid Request: Unrecognized Action' unless ['suspend', 'reactivate', 'cancel'].include?(new_status.to_s)
build_xml.tag!('ManageRecurringPaymentsProfileStatusReq', 'xmlns' => PAYPAL_NAMESPACE) do |xml|
xml.tag!('ManageRecurringPaymentsProfileStatusRequest', 'xmlns:n2' => EBAY_NAMESPACE) do |xml|
xml.tag!(NS2 + 'Version', API_VERSION)
xml.tag!(NS2 + 'ManageRecurringPaymentsProfileStatusRequestDetails') do
xml.tag!(NS2 + 'ProfileID', profile_id) # Required
xml.tag!(NS2 + 'Note', options[:description]) unless options[:description].blank? # Optional
xml.tag!(NS2 + 'Action', new_status.to_s.capitalize) # Required
end
end
end
end
def request_recurring_details(profile_id)
raise ArgumentError, 'Invalid Request: Missing Profile ID' if profile_id.blank?
build_xml.tag! 'GetRecurringPaymentsProfileDetailsReq', 'xmlns' => PAYPAL_NAMESPACE do |xml|
xml.tag! 'GetRecurringPaymentsProfileDetailsRequest', 'xmlns:n2' => EBAY_NAMESPACE do |xml|
xml.tag!(NS2 + 'Version', API_VERSION)
xml.tag! 'ProfileID', profile_id
end
end
end
def get_pay_period(period) #:nodoc:
case period
when :daily then [1, 'Day']
when :weekly then [1, 'Week']
when :biweekly then [2, 'Week']
when :semimonthly then [1, 'SemiMonth']
when :quadweekly then [4, 'Week']
when :monthly then [1, 'Month']
when :quarterly then [3, 'Month']
when :semiyearly then [6, 'Month']
when :yearly then [1, 'Year']
end
end
def format_rp_date(time)
case time
when Time, Date then time.strftime("%Y-%m-%dT%H:%M:%S")
else
time.to_s
end
end
def build_xml
Builder::XmlMarkup.new :indent => 2
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment