Class: PayPalSDK::IPN::Notification

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-paypal-extended/ipn/notification.rb

Overview

Parser and handler for incoming instant payment notifications from Paypal. The example shows a typical handler in a Rails application. Note that this is an example, please read the Paypal API documentation for all the details on creating a safe payment controller.

Example

class BackendController < ApplicationController
  def paypal_ipn
    notify = Paypal::Notification.new(request.raw_post, false)
    order = Order.find(notify.item_id)

    # Verify this IPN with Paypal.
    if notify.acknowledge
      # Paypal said this IPN is legit.
      begin
        if notify.complete? && order.total == notify.amount
          begin
            order.status = 'success'
            shop.ship(order)
            order.save!
          rescue => e
            order.status = 'failed'
            order.save!
            raise
          end
        else
          logger.error("We received a payment notification, but the " <<
                       "payment doesn't seem to be complete. Please " <<
                       "investigate. Transaction ID #{notify.transaction_id}.")
        end
    else
      # Paypal said this IPN is not correct.
      # ... log possible hacking attempt here ...
    end

    render :nothing => true
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(post, use_production = false) ⇒ Notification

Creates a new Paypal::Notification object. As the first argument, pass the raw POST data that you’ve received from Paypal.

In a Rails application this looks something like this:

def paypal_ipn
  paypal = Paypal::Notification.new(request.raw_post)
  ...
end


94
95
96
97
98
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 94

def initialize(post, use_production = false)
  @ipn_url = use_production ? PayPalSDK::Config::PRODUCTION_IPN_URL : PayPalSDK::Config::SANDBOX_IPN_URL
  empty!
  parse(post)
end

Instance Attribute Details

#ipn_urlObject

The IPN URL to connect to. Defaults to production



77
78
79
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 77

def ipn_url
  @ipn_url
end

#paramsObject

The parsed Paypal IPN data parameters.



80
81
82
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 80

def params
  @params
end

#rawObject

The raw Paypal IPN data that was received.



83
84
85
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 83

def raw
  @raw
end

Instance Method Details

#acknowledgeObject

Acknowledge the transaction to paypal. This method has to be called after a new IPN arrives. Paypal will verify that all the information we received are correct and will return a ok or a fail.

Example:

def paypal_ipn
  notify = PaypalNotification.new(request.raw_post)

  if notify.acknowledge 
    ... process order ... if notify.complete?
  else
    ... log possible hacking attempt ...
  end
end

Raises:



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 149

def acknowledge      
  payload = raw
  
  uri = URI.parse(self.ipn_url)
  request_path = "#{uri.path}?cmd=_notify-validate"
  
  request = Net::HTTP::Post.new(request_path)
  request['Content-Length'] = "#{payload.size}"
  request['User-Agent']     = "ruby-paypal-extended -- http://github.com/MicahWedemeyer/ruby-paypal-extended"
  
  http = Net::HTTP.new(uri.host, uri.port)
  
  if uri.scheme == "https"
    http.use_ssl = true
    # http://www.ruby-lang.org/en/news/2007/10/04/net-https-vulnerability/
    if http.respond_to?(:enable_post_connection_check)
      http.verify_mode = OpenSSL::SSL::VERIFY_PEER
      http.enable_post_connection_check = true
      store = OpenSSL::X509::Store.new
      store.set_default_paths
      http.cert_store = store
    else
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
  end
  
  request = http.request(request, payload)
  
  raise IPNException.new("Faulty paypal result: #{request.body}") unless ["VERIFIED", "INVALID"].include?(request.body)
  
  request.body == "VERIFIED"
end

#empty!Object

reset the notification.



129
130
131
132
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 129

def empty!
  @params  = {}
  @raw     = ""      
end

#payment_dateObject

When was this payment received by the client. sometimes it can happen that we get the notification much later. One possible scenario is that our web application was down. In this case paypal tries several times an hour to inform us about the notification



109
110
111
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 109

def payment_date
  Time.parse(params['payment_date'])
end

#statusObject

Returns the status of this transaction.



101
102
103
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 101

def status
  params['payment_status']
end

#test?Boolean

This is the invocie which you passed to paypal



124
125
126
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 124

def test?
  params['test_ipn'] == '1'
end

#transaction_idObject

Id of this transaction (paypal number)



114
115
116
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 114

def transaction_id
  params['txn_id']
end

#typeObject

What type of transaction are we dealing with?



119
120
121
# File 'lib/ruby-paypal-extended/ipn/notification.rb', line 119

def type
  params['txn_type']
end