Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save vijjunyros/1139026 to your computer and use it in GitHub Desktop.

Select an option

Save vijjunyros/1139026 to your computer and use it in GitHub Desktop.

Revisions

  1. @dmitriy-kiriyenko dmitriy-kiriyenko created this gist Jul 1, 2011.
    140 changes: 140 additions & 0 deletions paypal_recurring_gateway.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,140 @@
    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