Created
July 1, 2011 08:22
-
-
Save dmitriy-kiriyenko/1058090 to your computer and use it in GitHub Desktop.
Paypal Recurring Gateway, based on ActiveMerchant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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