Class: Paypal::Notification

Inherits:
Object
  • Object
show all
Defined in:
lib/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)

    order = Order.find(notify.item_id)

    if notify.acknowledge 
      begin

        if notify.complete? and order.total == notify.amount
          order.status = 'success' 

          shop.ship(order)
        else
          logger.error("Failed to verify Paypal's notification, please investigate")
        end

      rescue => e
        order.status        = 'failed'      
        raise
      ensure
        order.save
      end
    end

    render :nothing
  end
end

Constant Summary collapse

@@ipn_url =
'https://www.sandbox.paypal.com/cgi-bin/webscr'
@@paypal_cert =
"""
-----BEGIN CERTIFICATE-----
MIIDoTCCAwqgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBmDELMAkGA1UEBhMCVVMx
EzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBKb3NlMRUwEwYDVQQK
EwxQYXlQYWwsIEluYy4xFjAUBgNVBAsUDXNhbmRib3hfY2VydHMxFDASBgNVBAMU
C3NhbmRib3hfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0
MDQxOTA3MDI1NFoXDTM1MDQxOTA3MDI1NFowgZgxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEVMBMGA1UEChMMUGF5
UGFsLCBJbmMuMRYwFAYDVQQLFA1zYW5kYm94X2NlcnRzMRQwEgYDVQQDFAtzYW5k
Ym94X2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG
9w0BAQEFAAOBjQAwgYkCgYEAt5bjv/0N0qN3TiBL+1+L/EjpO1jeqPaJC1fDi+cC
6t6tTbQ55Od4poT8xjSzNH5S48iHdZh0C7EqfE1MPCc2coJqCSpDqxmOrO+9QXsj
HWAnx6sb6foHHpsPm7WgQyUmDsNwTWT3OGR398ERmBzzcoL5owf3zBSpRP0NlTWo
nPMCAwEAAaOB+DCB9TAdBgNVHQ4EFgQUgy4i2asqiC1rp5Ms81Dx8nfVqdIwgcUG
A1UdIwSBvTCBuoAUgy4i2asqiC1rp5Ms81Dx8nfVqdKhgZ6kgZswgZgxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEV
MBMGA1UEChMMUGF5UGFsLCBJbmMuMRYwFAYDVQQLFA1zYW5kYm94X2NlcnRzMRQw
EgYDVQQDFAtzYW5kYm94X2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNv
bYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFc288DYGX+GX2+W
P/dwdXwficf+rlG+0V9GBPJZYKZJQ069W/ZRkUuWFQ+Opd2yhPpneGezmw3aU222
CGrdKhOrBJRRcpoO3FjHHmXWkqgbQqDWdG7S+/l8n1QfDPp+jpULOrcnGEUY41Im
jZJTylbJQ1b5PBBjGiP0PpK48cdF
-----END CERTIFICATE-----
"""

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(post) ⇒ Notification

Creates a new paypal object. Pass the raw html you got from paypal in. In a rails application this looks something like this

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


93
94
95
96
# File 'lib/notification.rb', line 93

def initialize(post)
  empty!
  parse(post)
end

Instance Attribute Details

#paramsObject

Returns the value of attribute params.



41
42
43
# File 'lib/notification.rb', line 41

def params
  @params
end

#rawObject

Returns the value of attribute raw.



42
43
44
# File 'lib/notification.rb', line 42

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

Raises:

  • (StandardError)


193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/notification.rb', line 193

def acknowledge      
  payload =  raw
  
  uri = URI.parse(self.class.ipn_url)
  request_path = "#{uri.path}?cmd=_notify-validate"
  
  request = Net::HTTP::Post.new(request_path)
  request['Content-Length'] = "#{payload.size}"
  request['User-Agent']     = "paypal-ruby -- http://rubyforge.org/projects/paypal/"

  http = Net::HTTP.new(uri.host, uri.port)

  http.verify_mode    = OpenSSL::SSL::VERIFY_NONE unless @ssl_strict
  http.use_ssl        = true

  request = http.request(request, payload)
    
  raise StandardError.new("Faulty paypal result: #{request.body}") unless ["VERIFIED", "INVALID"].include?(request.body)
  
  request.body == "VERIFIED"
end

#amountObject

This combines the gross and currency and returns a proper Money object. this requires the money library located at dist.leetsoft.com/api/money



168
169
170
171
# File 'lib/notification.rb', line 168

def amount
  return Money.new(gross_cents, currency) rescue ArgumentError
  return Money.new(gross_cents) # maybe you have an own money object which doesn't take a currency?
end

#complete?Boolean

Was the transaction complete?

Returns:

  • (Boolean)


99
100
101
# File 'lib/notification.rb', line 99

def complete?
  status == "Completed"
end

#currencyObject

What currency have we been dealing with



138
139
140
# File 'lib/notification.rb', line 138

def currency
  params['mc_currency']
end

#empty!Object

reset the notification.



174
175
176
177
# File 'lib/notification.rb', line 174

def empty!
  @params  = Hash.new
  @raw     = ""      
end

#feeObject

the markup paypal charges for the transaction



133
134
135
# File 'lib/notification.rb', line 133

def fee
  params['mc_fee']
end

#grossObject

the money amount we received in X.2 decimal.



128
129
130
# File 'lib/notification.rb', line 128

def gross
  params['mc_gross']
end

#gross_centsObject



162
163
164
# File 'lib/notification.rb', line 162

def gross_cents
  (gross.to_f * 100.0).round
end

#invoiceObject

This is the custom field which you passed to paypal



148
149
150
# File 'lib/notification.rb', line 148

def invoice
  params['invoice']
end

#item_idObject

This is the item number which we submitted to paypal



143
144
145
# File 'lib/notification.rb', line 143

def item_id
  params['item_number']
end

#received_atObject

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



107
108
109
# File 'lib/notification.rb', line 107

def received_at
  Time.parse params['payment_date']
end

#statusObject

Whats the status of this transaction?



112
113
114
# File 'lib/notification.rb', line 112

def status
  params['payment_status']
end

#test?Boolean

This is the invocie which you passed to paypal

Returns:

  • (Boolean)


153
154
155
# File 'lib/notification.rb', line 153

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

#transaction_idObject

Id of this transaction (paypal number)



117
118
119
# File 'lib/notification.rb', line 117

def transaction_id
  params['txn_id']
end

#typeObject

What type of transaction are we dealing with?

"cart" "send_money" "web_accept" are possible here.


123
124
125
# File 'lib/notification.rb', line 123

def type
  params['txn_type']
end