module ActiveMerchant::Billing::PaypalCommonAPI

This module is included in both PaypalGateway and PaypalExpressGateway

Constants

API_VERSION
AUSTRALIAN_STATES
CREDENTIALS_NAMESPACES
EBAY_NAMESPACE
ENVELOPE_NAMESPACES
FRAUD_REVIEW_CODE
PAYPAL_NAMESPACE
SUCCESS_CODES
URLS

Public Class Methods

included(base) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 43
def self.included(base)
  base.default_currency = 'USD'
  base.cattr_accessor :pem_file
  base.cattr_accessor :signature
  base.live_url = URLS[:live][:signature]
  base.test_url = URLS[:test][:signature]
end
new(options = {}) click to toggle source

The gateway must be configured with either your PayPal PEM file or your PayPal API Signature. Only one is required.

:pem The text of your PayPal PEM file. Note

this is not the path to file, but its
contents. If you are only using one PEM
file on your site you can declare it
globally and then you won't need to
include this option

:signature The text of your PayPal signature.

If you are only using one API Signature
on your site you can declare it
globally and then you won't need to
include this option
Calls superclass method
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 66
def initialize(options = {})
  requires!(options, :login, :password)

  headers = {'X-PP-AUTHORIZATION' => options.delete(:auth_signature), 'X-PAYPAL-MESSAGE-PROTOCOL' => 'SOAP11'} if options[:auth_signature]
  options = {
    :pem => pem_file,
    :signature => signature,
    :headers => headers || {}
  }.update(options)


  if options[:pem].blank? && options[:signature].blank?
    raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
  end

  super(options)
end

Public Instance Methods

authorize_transaction(transaction_id, money, options = {}) click to toggle source

DoAuthorization takes the transaction_id returned when you call DoExpressCheckoutPayment with a PaymentAction of 'Order'. When you did that, you created an order authorization subject to settlement with PayPal DoAuthorization and DoCapture

Parameters:

  • :transaction_id – The ID returned by DoExpressCheckoutPayment with a PaymentAction of 'Order'.

  • :money – The amount of money to be authorized for this purchase.

# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 243
def authorize_transaction(transaction_id, money, options = {})
  commit 'DoAuthorization', build_do_authorize(transaction_id, money, options)
end
balance(return_all_currencies = false) click to toggle source

Parameters:

  • :return_all_currencies – Either '1' or '0'

    0 – Return only the balance for the primary currency holding.
    1 – Return the balance for each currency holding.
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 225
def balance(return_all_currencies = false)
  clean_currency_argument = case return_all_currencies
                            when 1, '1' , true; '1'
                            else
                              '0'
                            end
  commit 'GetBalance', build_get_balance(clean_currency_argument)
end
capture(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 88
def capture(money, authorization, options = {})
  commit 'DoCapture', build_capture_request(money, authorization, options)
end
credit(money, identification, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 126
def credit(money, identification, options = {})
  ActiveMerchant.deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
  refund(money, identification, options)
end
manage_pending_transaction(transaction_id, action) click to toggle source

The ManagePendingTransactionStatus API operation accepts or denies a pending transaction held by Fraud Management Filters.

Parameters:

  • :transaction_id – The ID of the transaction held by Fraud Management Filters.

  • :action – Either 'Accept' or 'Deny'

# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 254
def manage_pending_transaction(transaction_id, action)
  commit 'ManagePendingTransactionStatus', build_manage_pending_transaction_status(transaction_id, action)
end
reauthorize(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 84
def reauthorize(money, authorization, options = {})
  commit 'DoReauthorization', build_reauthorize_request(money, authorization, options)
end
reference_transaction(money, options = {}) click to toggle source

For full documentation see Paypal API Reference:

Parameter:

  • :money – (Required) The amount of this new transaction,

required fo the payment details portion of this request

Options:

  • :reference_id – (Required) A transaction ID from a previous purchase, such as a credit card charge using the DoDirectPayment API, or a billing agreement ID.

  • :payment_action – (Optional) How you want to obtain payment. It is one of the following values:

    Authorization – This payment is a basic authorization subject to settlement with PayPal Authorization and Capture.
    Sale – This is a final sale for which you are requesting payment.
  • :ip_address – (Optional) IP address of the buyer’s browser.

Note: PayPal records this IP addresses as a means to detect possible fraud.

  • :req_confirm_shipping – Whether you require that the buyer’s shipping address on file with PayPal be a confirmed address. You must have permission from PayPal to not require a confirmed address. It is one of the following values:

    0 – You do not require that the buyer’s shipping address be a confirmed address.
    1 – You require that the buyer’s shipping address be a confirmed address.
  • :merchant_session_id – (Optional) Your buyer session identification token.

  • :return_fmf_details – (Optional) Flag to indicate whether you want the results returned by Fraud Management Filters. By default, you do not receive this information. It is one of the following values:

    0 – Do not receive FMF details (default)
    1 – Receive FMF details
  • :soft_descriptor – (Optional) Per transaction description of the payment that is passed to the consumer’s credit card statement. If the API request provides a value for the soft descriptor field, the full descriptor displayed on the buyer’s statement has the following format:

    <PP * | PAYPAL *><Merchant descriptor as set in the Payment Receiving Preferences><1 space><soft descriptor>
    The soft descriptor can contain only the following characters:
    
    Alphanumeric characters
    - (dash)
    * (asterisk)
    . (period)
    {space}
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 167
def reference_transaction(money, options = {})
  requires!(options, :reference_id)
  commit 'DoReferenceTransaction', build_reference_transaction_request(money, options)
end
refund(money, identification, options = {}) click to toggle source

Refunds a transaction.

For a full refund pass nil for the amount:

gateway.refund nil, 'G39883289DH238'

This will automatically make the :refund_type be “Full”.

For a partial refund just pass the amount as usual:

gateway.refund 100, 'UBU83983N920'
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 122
def refund(money, identification, options = {})
  commit 'RefundTransaction', build_refund_request(money, identification, options)
end
transaction_details(transaction_id) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 172
def transaction_details(transaction_id)
  commit 'GetTransactionDetails', build_get_transaction_details(transaction_id)
end
transfer(*args) click to toggle source

Transfer money to one or more recipients.

gateway.transfer 1000, 'bob@example.com',
  :subject => "The money I owe you", :note => "Sorry it's so late"

gateway.transfer [1000, 'fred@example.com'],
  [2450, 'wilma@example.com', :note => 'You will receive another payment on 3/24'],
  [2000, 'barney@example.com'],
  :subject => "Your Earnings", :note => "Thanks for your business."
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 102
def transfer(*args)
  commit 'MassPay', build_mass_pay_request(*args)
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 106
def void(authorization, options = {})
  commit 'DoVoid', build_void_request(authorization, options)
end

Private Instance Methods

add_address(xml, element, address) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 526
def add_address(xml, element, address)
  return if address.nil?
  xml.tag! element do
    xml.tag! 'n2:Name', address[:name]
    xml.tag! 'n2:Street1', address[:address1]
    xml.tag! 'n2:Street2', address[:address2]
    xml.tag! 'n2:CityName', address[:city]
    xml.tag! 'n2:StateOrProvince', address[:state].blank? ? 'N/A' : address[:state]
    xml.tag! 'n2:Country', address[:country]
    xml.tag! 'n2:Phone', address[:phone] unless address[:phone].blank?
    xml.tag! 'n2:PostalCode', address[:zip]
  end
end
add_button_source(xml) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 598
def add_button_source(xml)
  button_source = (@options[:button_source] || application_id)
  if !empty?(button_source)
    xml.tag! 'n2:ButtonSource', button_source.to_s.slice(0, 32)
  end
end
add_credentials(xml) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 515
def add_credentials(xml)
  xml.tag! 'RequesterCredentials', CREDENTIALS_NAMESPACES do
    xml.tag! 'n1:Credentials' do
      xml.tag! 'n1:Username', @options[:login]
      xml.tag! 'n1:Password', @options[:password]
      xml.tag! 'n1:Subject', @options[:subject]
      xml.tag! 'n1:Signature', @options[:signature] unless @options[:signature].blank?
    end
  end
end
add_express_only_payment_details(xml, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 605
def add_express_only_payment_details(xml, options = {})
  add_optional_fields(xml,
                      %w{n2:NoteText          n2:SoftDescriptor
                         n2:TransactionId     n2:AllowedPaymentMethodType
                         n2:PaymentRequestID  n2:PaymentAction},
                      options)
end
add_optional_fields(xml, optional_fields, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 613
def add_optional_fields(xml, optional_fields, options = {})
  optional_fields.each do |optional_text_field|
    if optional_text_field =~ /(\w+:)(\w+)/
      ns = $1
      field = $2
      field_as_symbol = field.underscore.to_sym
    else
      ns = ''
      field = optional_text_field
      field_as_symbol = optional_text_field.underscore.to_sym
    end
    xml.tag! ns + field, options[field_as_symbol] unless options[field_as_symbol].blank?
  end
  xml
end
add_payment_details(xml, money, currency_code, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 556
def add_payment_details(xml, money, currency_code, options = {})
  xml.tag! 'n2:PaymentDetails' do
    xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code

    # All of the values must be included together and add up to the order total
    if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
      xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
      xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
      xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
      xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
    end

    xml.tag! 'n2:InsuranceTotal', localized_amount(options[:insurance_total], currency_code),'currencyID' => currency_code unless options[:insurance_total].blank?
    xml.tag! 'n2:ShippingDiscount', localized_amount(options[:shipping_discount], currency_code),'currencyID' => currency_code unless options[:shipping_discount].blank?
    xml.tag! 'n2:InsuranceOptionOffered', options[:insurance_option_offered] if options.has_key?(:insurance_option_offered)

    xml.tag! 'n2:OrderDescription', options[:description] unless options[:description].blank?

    # Custom field Character length and limitations: 256 single-byte alphanumeric characters
    xml.tag! 'n2:Custom', options[:custom] unless options[:custom].blank?

    xml.tag! 'n2:InvoiceID', (options[:order_id] || options[:invoice_id]) unless (options[:order_id] || options[:invoice_id]).blank?
    add_button_source(xml)

    # The notify URL applies only to DoExpressCheckoutPayment.
    # This value is ignored when set in SetExpressCheckout or GetExpressCheckoutDetails
    xml.tag! 'n2:NotifyURL', options[:notify_url] unless options[:notify_url].blank?

    add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) unless options[:shipping_address].blank?

    add_payment_details_items_xml(xml, options, currency_code) unless options[:items].blank?

    add_express_only_payment_details(xml, options) if options[:express_request]

    # Any value other than Y – This is not a recurring transaction
    # To pass Y in this field, you must have established a billing agreement with
    # the buyer specifying the amount, frequency, and duration of the recurring payment.
    # requires version 80.0 of the API
    xml.tag! 'n2:Recurring', options[:recurring] unless options[:recurring].blank?
  end
end
add_payment_details_items_xml(xml, options, currency_code) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 540
def add_payment_details_items_xml(xml, options, currency_code)
  options[:items].each do |item|
    xml.tag! 'n2:PaymentDetailsItem' do
      xml.tag! 'n2:Name', item[:name]
      xml.tag! 'n2:Number', item[:number]
      xml.tag! 'n2:Quantity', item[:quantity]
      if item[:amount]
        xml.tag! 'n2:Amount', item_amount(item[:amount], currency_code), 'currencyID' => currency_code
      end
      xml.tag! 'n2:Description', item[:description]
      xml.tag! 'n2:ItemURL', item[:url]
      xml.tag! 'n2:ItemCategory', item[:category] if item[:category]
    end
  end
end
authorization_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 649
def authorization_from(response)
  (
    response[:transaction_id] ||
    response[:authorization_id] ||
    response[:refund_transaction_id] ||
    response[:billing_agreement_id]
  )
end
build_capture_request(money, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 297
def build_capture_request(money, authorization, options)
  xml = Builder::XmlMarkup.new

  xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
    xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
      xml.tag! 'n2:Version', API_VERSION
      xml.tag! 'AuthorizationID', authorization
      xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
      xml.tag! 'CompleteType',  options[:complete_type] || 'Complete'
      xml.tag! 'InvoiceID', options[:order_id] unless options[:order_id].blank?
      xml.tag! 'Note', options[:description]
    end
  end

  xml.target!
end
build_do_authorize(transaction_id, money, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 276
def build_do_authorize(transaction_id, money, options = {})
  build_request_wrapper('DoAuthorization') do |xml|
    xml.tag! 'TransactionID', transaction_id
    xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
  end
end
build_get_balance(return_all_currencies) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 420
def build_get_balance(return_all_currencies)
  build_request_wrapper('GetBalance') do |xml|
    xml.tag! 'ReturnAllCurrencies', return_all_currencies unless return_all_currencies.nil?
  end
end
build_get_transaction_details(transaction_id) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 398
def build_get_transaction_details(transaction_id)
  build_request_wrapper('GetTransactionDetails') do |xml|
    xml.tag! 'TransactionID', transaction_id
  end
end
build_manage_pending_transaction_status(transaction_id, action) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 377
def build_manage_pending_transaction_status(transaction_id, action)
  build_request_wrapper('ManagePendingTransactionStatus') do |xml|
    xml.tag! 'TransactionID', transaction_id
    xml.tag! 'Action', action
  end
end
build_mass_pay_request(*args) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 344
def build_mass_pay_request(*args)
  default_options = args.last.is_a?(Hash) ? args.pop : {}
  recipients = args.first.is_a?(Array) ? args : [args]
  receiver_type = default_options[:receiver_type]

  xml = Builder::XmlMarkup.new

  xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
    xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
      xml.tag! 'n2:Version', API_VERSION
      xml.tag! 'EmailSubject', default_options[:subject] if default_options[:subject]
      xml.tag! 'ReceiverType', receiver_type if receiver_type
      recipients.each do |money, recipient, options|
        options ||= default_options
        xml.tag! 'MassPayItem' do
          if(!receiver_type || receiver_type == 'EmailAddress')
            xml.tag! 'ReceiverEmail', recipient
          elsif receiver_type == 'UserID'
            xml.tag! 'ReceiverID', recipient
          else
            raise ArgumentError.new("Unknown receiver_type: #{receiver_type}")
          end
          xml.tag! 'Amount', amount(money), 'currencyID' => (options[:currency] || currency(money))
          xml.tag! 'Note', options[:note] if options[:note]
          xml.tag! 'UniqueId', options[:unique_id] if options[:unique_id]
        end
      end
    end
  end

  xml.target!
end
build_reauthorize_request(money, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 283
def build_reauthorize_request(money, authorization, options)
  xml = Builder::XmlMarkup.new

  xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
    xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
      xml.tag! 'n2:Version', API_VERSION
      xml.tag! 'AuthorizationID', authorization
      xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
    end
  end

  xml.target!
end
build_reference_transaction_request(money, options) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 384
def build_reference_transaction_request(money, options)
  opts = options.dup
  opts[:ip_address] ||= opts[:ip]
  currency_code = opts[:currency] || currency(money)
  reference_transaction_optional_fields = %w{ n2:ReferenceID n2:PaymentAction
                                              n2:PaymentType n2:IPAddress
                                              n2:ReqConfirmShipping n2:MerchantSessionId
                                              n2:ReturnFMFDetails n2:SoftDescriptor }
  build_request_wrapper('DoReferenceTransaction', :request_details => true) do |xml|
    add_optional_fields(xml, reference_transaction_optional_fields, opts)
    add_payment_details(xml, money, currency_code, opts)
  end
end
build_refund_request(money, identification, options) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 314
def build_refund_request(money, identification, options)
  xml = Builder::XmlMarkup.new

  xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
    xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
      xml.tag! 'n2:Version', API_VERSION
      xml.tag! 'TransactionID', identification
      xml.tag! 'Amount', amount(money), 'currencyID' => (options[:currency] || currency(money)) if money.present?
      xml.tag! 'RefundType', (options[:refund_type] || (money.present? ? 'Partial' : 'Full'))
      xml.tag! 'Memo', options[:note] unless options[:note].blank?
    end
  end

  xml.target!
end
build_request(body) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 499
def build_request(body)
  xml = Builder::XmlMarkup.new

  xml.instruct!
  xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
    xml.tag! 'env:Header' do
      add_credentials(xml) unless @options[:headers] && @options[:headers]['X-PP-AUTHORIZATION']
    end

    xml.tag! 'env:Body' do
      xml << body
    end
  end
  xml.target!
end
build_request_wrapper(action, options = {}) { |xml| ... } click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 259
def build_request_wrapper(action, options = {})
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! action + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
    xml.tag! action + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
      xml.tag! 'n2:Version', API_VERSION
      if options[:request_details]
        xml.tag! 'n2:' + action + 'RequestDetails' do
          yield(xml)
        end
      else
        yield(xml)
      end
    end
  end
  xml.target!
end
build_void_request(authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 330
def build_void_request(authorization, options)
  xml = Builder::XmlMarkup.new

  xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
    xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
      xml.tag! 'n2:Version', API_VERSION
      xml.tag! 'AuthorizationID', authorization
      xml.tag! 'Note', options[:description]
    end
  end

  xml.target!
end
commit(action, request) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 633
def commit(action, request)
  response = parse(action, ssl_post(endpoint_url, build_request(request), @options[:headers]))

  build_response(successful?(response), message_from(response), response,
    :test => test?,
    :authorization => authorization_from(response),
    :fraud_review => fraud_review?(response),
    :avs_result => { :code => response[:avs_code] },
    :cvv_result => response[:cvv2_code]
  )
end
date_to_iso(date) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 666
def date_to_iso(date)
  (date.is_a?(Date) ? date.to_time : date).utc.iso8601
end
endpoint_url() click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 629
def endpoint_url
  URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
end
fraud_review?(response) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 645
def fraud_review?(response)
  response[:error_codes] == FRAUD_REVIEW_CODE
end
item_amount(amount, currency_code) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 670
def item_amount(amount, currency_code)
  if amount.to_i < 0 && Gateway.non_fractional_currency?(currency_code)
    amount(amount).to_f.floor
  else
    localized_amount(amount, currency_code)
  end
end
legacy_parse(action, xml) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 446
def legacy_parse(action, xml)
  response = {}

  error_messages = []
  error_codes = []

  xml = REXML::Document.new(xml)
  if root = REXML::XPath.first(xml, "//#{action}Response")
    root.elements.each do |node|
      case node.name
      when 'Errors'
        short_message = nil
        long_message = nil

        node.elements.each do |child|
          case child.name
          when "LongMessage"
            long_message = child.text unless child.text.blank?
          when "ShortMessage"
            short_message = child.text unless child.text.blank?
          when "ErrorCode"
            error_codes << child.text unless child.text.blank?
          end
        end

        if message = long_message || short_message
          error_messages << message
        end
      else
        legacy_parse_element(response, node)
      end
    end
    response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
    response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
  elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
    legacy_parse_element(response, root)
    response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
  end

  response
end
legacy_parse_element(response, node) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 488
def legacy_parse_element(response, node)
  if node.has_elements?
    node.elements.each{|e| legacy_parse_element(response, e) }
  else
    response[node.name.underscore.to_sym] = node.text
    node.attributes.each do |k, v|
      response["#{node.name.underscore}_#{k.underscore}".to_sym] = v if k == 'currencyID'
    end
  end
end
message_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 662
def message_from(response)
  response[:message] || response[:ack]
end
parse(action, xml) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 426
def parse(action, xml)
  legacy_hash = legacy_parse(action, xml)
  xml = strip_attributes(xml)
  hash = Hash.from_xml(xml)
  hash = hash.fetch('Envelope').fetch('Body').fetch("#{action}Response")
  hash = hash["#{action}ResponseDetails"] if hash["#{action}ResponseDetails"]

  legacy_hash.merge(hash)
rescue IndexError
  legacy_hash.merge(hash['Envelope']['Body'])
end
strip_attributes(xml) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 438
def strip_attributes(xml)
  xml = REXML::Document.new(xml)
  REXML::XPath.each(xml, '//SOAP-ENV:Envelope//*[@*]') do |el|
    el.attributes.each_attribute { |a| a.remove }
  end
  xml.to_s
end
successful?(response) click to toggle source
# File lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb, line 658
def successful?(response)
  SUCCESS_CODES.include?(response[:ack])
end