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