class ActiveMerchant::Billing::PayflowGateway

Constants

RECURRING_ACTIONS

Public Instance Methods

authorize(money, credit_card_or_reference, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 17
def authorize(money, credit_card_or_reference, options = {})
  request = build_sale_or_authorization_request(:authorization, money, credit_card_or_reference, options)

  commit(request, options)
end
cancel_recurring(profile_id) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 86
def cancel_recurring(profile_id)
  ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE

  request = build_recurring_request(:cancel, 0, :profile_id => profile_id)
  commit(request, options.merge(:request_type => :recurring))
end
credit(money, funding_source, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 29
def credit(money, funding_source, options = {})
  if funding_source.is_a?(String)
    ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
    # Perform referenced credit
    refund(money, funding_source, options)
  elsif card_brand(funding_source) == 'check'
    # Perform non-referenced credit
    request = build_check_request(:credit, money, funding_source, options)
    commit(request, options)
  else
    request = build_credit_card_request(:credit, money, funding_source, options)
    commit(request, options)
  end
end
express() click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 100
def express
  @express ||= PayflowExpressGateway.new(@options)
end
purchase(money, funding_source, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 23
def purchase(money, funding_source, options = {})
  request = build_sale_or_authorization_request(:purchase, money, funding_source, options)

  commit(request, options)
end
recurring(money, credit_card, options = {}) click to toggle source

Adds or modifies a recurring Payflow profile. See the Payflow Pro Recurring Billing Guide for more details: www.paypal.com/en_US/pdf/PayflowPro_RecurringBilling_Guide.pdf

Several options are available to customize the recurring profile:

  • profile_id - is only required for editing a recurring profile

  • starting_at - takes a Date, Time, or string in mmddyyyy format. The date must be in the future.

  • name - The name of the customer to be billed. If not specified, the name from the credit card is used.

  • periodicity - The frequency that the recurring payments will occur at. Can be one of

:bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily, :semimonthly, :quadweekly, :quarterly, :semiyearly

  • payments - The term, or number of payments that will be made

  • comment - A comment associated with the profile

# File lib/active_merchant/billing/gateways/payflow.rb, line 76
def recurring(money, credit_card, options = {})
  ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE

  options[:name] = credit_card.name if options[:name].blank? && credit_card
  request = build_recurring_request(options[:profile_id] ? :modify : :add, money, options) do |xml|
    add_credit_card(xml, credit_card, options) if credit_card
  end
  commit(request, options.merge(:request_type => :recurring))
end
recurring_inquiry(profile_id, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 93
def recurring_inquiry(profile_id, options = {})
  ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE

  request = build_recurring_request(:inquiry, nil, options.update(:profile_id => profile_id))
  commit(request, options.merge(:request_type => :recurring))
end
refund(money, reference, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 44
def refund(money, reference, options = {})
  commit(build_reference_request(:credit, money, reference, options), options)
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 108
def scrub(transcript)
  transcript.
    gsub(%r((<CardNum>)[^<]*(</CardNum>)), '\1[FILTERED]\2').
    gsub(%r((<CVNum>)[^<]*(</CVNum>)), '\1[FILTERED]\2').
    gsub(%r((<AcctNum>)[^<]*(</AcctNum>)), '\1[FILTERED]\2').
    gsub(%r((<Password>)[^<]*(</Password>)), '\1[FILTERED]\2')
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 104
def supports_scrubbing?
  true
end
verify(payment, options={}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 48
def verify(payment, options={})
  if credit_card_type(payment) == 'Amex'
    MultiResponse.run(:use_first_response) do |r|
      r.process { authorize(100, payment, options) }
      r.process(:ignore_result) { void(r.authorization, options) }
    end
  else
    authorize(0, payment, options)
  end
end
verify_credentials() click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 59
def verify_credentials
  response = void('0')
  response.params['result'] != '26'
end

Private Instance Methods

add_credit_card(xml, credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 257
def add_credit_card(xml, credit_card, options = {})
  xml.tag! 'Card' do
    xml.tag! 'CardType', credit_card_type(credit_card)
    xml.tag! 'CardNum', credit_card.number
    xml.tag! 'ExpDate', expdate(credit_card)
    xml.tag! 'NameOnCard', credit_card.first_name
    xml.tag! 'CVNum', credit_card.verification_value if credit_card.verification_value?

    if options[:three_d_secure]
      three_d_secure = options[:three_d_secure]
      xml.tag! 'BuyerAuthResult' do
        xml.tag! 'Status', three_d_secure[:status] unless three_d_secure[:status].blank?
        xml.tag! 'AuthenticationId', three_d_secure[:authentication_id] unless three_d_secure[:authentication_id].blank?
        xml.tag! 'PAReq', three_d_secure[:pareq] unless three_d_secure[:pareq].blank?
        xml.tag! 'ACSUrl', three_d_secure[:acs_url] unless three_d_secure[:acs_url].blank?
        xml.tag! 'ECI', three_d_secure[:eci] unless three_d_secure[:eci].blank?
        xml.tag! 'CAVV', three_d_secure[:cavv] unless three_d_secure[:cavv].blank?
        xml.tag! 'XID', three_d_secure[:xid] unless three_d_secure[:xid].blank?
      end
    end

    xml.tag! 'ExtData', 'Name' => 'LASTNAME', 'Value' =>  credit_card.last_name
  end
end
add_fields(xml_doc, options_fields) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 225
def add_fields(xml_doc, options_fields)
  fields_to_add = JSON.parse(options_fields)
  check_fields('Invoice', fields_to_add, xml_doc)
  xml_doc.root.to_s
end
add_level_two_three_fields(xml_string, options) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 194
def add_level_two_three_fields(xml_string, options)
  if options[:level_two_fields] || options[:level_three_fields]
    xml_doc = Nokogiri::XML.parse(xml_string)
    %i[level_two_fields level_three_fields].each do |fields|
      xml_string = add_fields(xml_doc, options[fields]) if options[fields]
    end
  end
  xml_string
end
build_check_request(action, money, check, options) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 231
def build_check_request(action, money, check, options)
  xml = Builder::XmlMarkup.new
  xml.tag! TRANSACTIONS[action] do
    xml.tag! 'PayData' do
      xml.tag! 'Invoice' do
        xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
        xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank?
        xml.tag! 'Description', options[:description] unless options[:description].blank?
        xml.tag! 'OrderDesc', options[:order_desc] unless options[:order_desc].blank?
        xml.tag! 'BillTo' do
          xml.tag! 'Name', check.name
        end
        xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
      end
      xml.tag! 'Tender' do
        xml.tag! 'ACH' do
          xml.tag! 'AcctType', check.account_type == 'checking' ? 'C' : 'S'
          xml.tag! 'AcctNum', check.account_number
          xml.tag! 'ABA', check.routing_number
        end
      end
    end
  end
  add_level_two_three_fields(xml.target!, options)
end
build_credit_card_request(action, money, credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 161
def build_credit_card_request(action, money, credit_card, options)
  xml = Builder::XmlMarkup.new
  xml.tag! TRANSACTIONS[action] do
    xml.tag! 'PayData' do
      xml.tag! 'Invoice' do
        xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
        xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank?
        xml.tag! 'Description', options[:description] unless options[:description].blank?
        xml.tag! 'OrderDesc', options[:order_desc] unless options[:order_desc].blank?
        # Comment and Comment2 will show up in manager.paypal.com as Comment1 and Comment2
        xml.tag! 'Comment', options[:comment] unless options[:comment].blank?
        xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank?
        xml.tag! 'TaxAmt', options[:taxamt] unless options[:taxamt].blank?
        xml.tag! 'FreightAmt', options[:freightamt] unless options[:freightamt].blank?
        xml.tag! 'DutyAmt', options[:dutyamt] unless options[:dutyamt].blank?
        xml.tag! 'DiscountAmt', options[:discountamt] unless options[:discountamt].blank?
        xml.tag! 'EMail', options[:email] unless options[:email].nil?

        billing_address = options[:billing_address] || options[:address]
        add_address(xml, 'BillTo', billing_address, options) if billing_address
        add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]

        xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
      end

      xml.tag! 'Tender' do
        add_credit_card(xml, credit_card, options)
      end
    end
  end
  add_level_two_three_fields(xml.target!, options)
end
build_recurring_request(action, money, options) { |xml| ... } click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 302
def build_recurring_request(action, money, options)
  unless RECURRING_ACTIONS.include?(action)
    raise StandardError, "Invalid Recurring Profile Action: #{action}"
  end

  xml = Builder::XmlMarkup.new
  xml.tag! 'RecurringProfiles' do
    xml.tag! 'RecurringProfile' do
      xml.tag! action.to_s.capitalize do
        unless [:cancel, :inquiry].include?(action)
          xml.tag! 'RPData' do
            xml.tag! 'Name', options[:name] unless options[:name].nil?
            xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
            xml.tag! 'PayPeriod', get_pay_period(options)
            xml.tag! 'Term', options[:payments] unless options[:payments].nil?
            xml.tag! 'Comment', options[:comment] unless options[:comment].nil?
            xml.tag! 'RetryNumDays', options[:retry_num_days] unless options[:retry_num_days].nil?
            xml.tag! 'MaxFailPayments', options[:max_fail_payments] unless options[:max_fail_payments].nil?

            if initial_tx = options[:initial_transaction]
              requires!(initial_tx, [:type, :authorization, :purchase])
              requires!(initial_tx, :amount) if initial_tx[:type] == :purchase

              xml.tag! 'OptionalTrans', TRANSACTIONS[initial_tx[:type]]
              xml.tag! 'OptionalTransAmt', amount(initial_tx[:amount]) unless initial_tx[:amount].blank?
            end

            if action == :add
              xml.tag! 'Start', format_rp_date(options[:starting_at] || Date.today + 1)
            else
              xml.tag! 'Start', format_rp_date(options[:starting_at]) unless options[:starting_at].nil?
            end

            xml.tag! 'EMail', options[:email] unless options[:email].nil?

            billing_address = options[:billing_address] || options[:address]
            add_address(xml, 'BillTo', billing_address, options) if billing_address
            add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
          end
          xml.tag! 'Tender' do
            yield xml
          end
        end
        if action != :add
          xml.tag! 'ProfileID', options[:profile_id]
        end
        if action == :inquiry
          xml.tag! 'PaymentHistory', (options[:history] ? 'Y' : 'N')
        end
      end
    end
  end
end
build_reference_sale_or_authorization_request(action, money, reference, options) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 128
def build_reference_sale_or_authorization_request(action, money, reference, options)
  xml = Builder::XmlMarkup.new
  xml.tag! TRANSACTIONS[action] do
    xml.tag! 'PayData' do
      xml.tag! 'Invoice' do
        # Fields accepted by PayFlow and recommended to be provided even for Reference Transaction, per Payflow docs.
        xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
        xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank?
        xml.tag! 'Description', options[:description] unless options[:description].blank?
        xml.tag! 'OrderDesc', options[:order_desc] unless options[:order_desc].blank?
        xml.tag! 'Comment', options[:comment] unless options[:comment].blank?
        xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank?
        xml.tag! 'TaxAmt', options[:taxamt] unless options[:taxamt].blank?
        xml.tag! 'FreightAmt', options[:freightamt] unless options[:freightamt].blank?
        xml.tag! 'DutyAmt', options[:dutyamt] unless options[:dutyamt].blank?
        xml.tag! 'DiscountAmt', options[:discountamt] unless options[:discountamt].blank?

        billing_address = options[:billing_address] || options[:address]
        add_address(xml, 'BillTo', billing_address, options) if billing_address
        add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]

        xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
      end
      xml.tag! 'Tender' do
        xml.tag! 'Card' do
          xml.tag! 'ExtData', 'Name' => 'ORIGID', 'Value' =>  reference
        end
      end
    end
  end
  xml.target!
end
build_response(success, message, response, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 378
def build_response(success, message, response, options = {})
  PayflowResponse.new(success, message, response, options)
end
build_sale_or_authorization_request(action, money, funding_source, options) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 118
def build_sale_or_authorization_request(action, money, funding_source, options)
  if funding_source.is_a?(String)
    build_reference_sale_or_authorization_request(action, money, funding_source, options)
  elsif card_brand(funding_source) == 'check'
    build_check_request(action, money, funding_source, options)
  else
    build_credit_card_request(action, money, funding_source, options)
  end
end
check_fields(parent, fields, xml_doc) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 204
def check_fields(parent, fields, xml_doc)
  fields.each do |k, v|
    if v.is_a? String
      new_node = Nokogiri::XML::Node.new(k, xml_doc)
      new_node.add_child(v)
      xml_doc.at_css(parent).add_child(new_node)
    else
      check_subparent_before_continuing(parent, k, xml_doc)
      check_fields(k, v, xml_doc)
    end
  end
  xml_doc
end
check_subparent_before_continuing(parent, subparent, xml_doc) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 218
def check_subparent_before_continuing(parent, subparent, xml_doc)
  unless xml_doc.at_css(subparent)
    subparent_node = Nokogiri::XML::Node.new(subparent, xml_doc)
    xml_doc.at_css(parent).add_child(subparent_node)
  end
end
credit_card_type(credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 282
def credit_card_type(credit_card)
  return '' if card_brand(credit_card).blank?

  CARD_MAPPING[card_brand(credit_card).to_sym]
end
expdate(creditcard) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 288
def expdate(creditcard)
  year  = sprintf('%.4i', creditcard.year.to_s.sub(/^0+/, ''))
  month = sprintf('%.2i', creditcard.month.to_s.sub(/^0+/, ''))

  "#{year}#{month}"
end
format_rp_date(time) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 370
def format_rp_date(time)
  case time
  when Time, Date then time.strftime('%m%d%Y')
  else
    time.to_s
  end
end
get_pay_period(options) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 356
def get_pay_period(options)
  requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily, :semimonthly, :quadweekly, :quarterly, :semiyearly])
  case options[:periodicity]
  when :weekly then 'Weekly'
  when :biweekly then 'Bi-weekly'
  when :semimonthly then 'Semi-monthly'
  when :quadweekly then 'Every four weeks'
  when :monthly then 'Monthly'
  when :quarterly then 'Quarterly'
  when :semiyearly then 'Semi-yearly'
  when :yearly then 'Yearly'
  end
end
startdate(creditcard) click to toggle source
# File lib/active_merchant/billing/gateways/payflow.rb, line 295
def startdate(creditcard)
  year  = format(creditcard.start_year, :two_digits)
  month = format(creditcard.start_month, :two_digits)

  "#{month}#{year}"
end