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 and notify.business == '[email protected]'
          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)


237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/notification.rb', line 237

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



212
213
214
215
# File 'lib/notification.rb', line 212

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

#businessObject

This is the email address associated to the paypal account that recieved the payment.



157
158
159
# File 'lib/notification.rb', line 157

def business
  params['business']
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



146
147
148
# File 'lib/notification.rb', line 146

def currency
  params['mc_currency']
end

#customObject

This is the custom field which you passed to paypal



177
178
179
# File 'lib/notification.rb', line 177

def custom
  params['custom']
end

#denied?Boolean

Returns:

  • (Boolean)


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

def denied?
  status == "Denied"
end

#empty!Object

reset the notification.



218
219
220
221
# File 'lib/notification.rb', line 218

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

#exchange_rateObject

The exchange rate used if there was a conversion.



202
203
204
# File 'lib/notification.rb', line 202

def exchange_rate
  params['exchange_rate']
end

#failed?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/notification.rb', line 103

def failed?
  status == "Failed"
end

#feeObject

the markup paypal charges for the transaction



141
142
143
# File 'lib/notification.rb', line 141

def fee
  params['mc_fee']
end

#grossObject

the money amount we received in X.2 decimal.



136
137
138
# File 'lib/notification.rb', line 136

def gross
  params['mc_gross']
end

#gross_centsObject



206
207
208
# File 'lib/notification.rb', line 206

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

#invoiceObject

This is the invocie which you passed to paypal



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

def invoice
  params['invoice']
end

#item_idObject

This is the item number which we submitted to paypal



151
152
153
# File 'lib/notification.rb', line 151

def item_id
  params['item_number']
end

#item_nameObject

This is the item_name which you passed to paypal



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

def item_name
  params['item_name']
end

#memoObject

Memo entered by customer if any



192
193
194
# File 'lib/notification.rb', line 192

def memo
  params['memo']
end

#payment_typeObject

Well, the payment type.



197
198
199
# File 'lib/notification.rb', line 197

def payment_type
  params['payment_type']
end

#pending_reasonObject

Reason for pending status, nil if status is not pending.



182
183
184
# File 'lib/notification.rb', line 182

def pending_reason
  params['pending_reason']
end

#reason_codeObject

Reason for reversed status, nil if status is not reversed.



187
188
189
# File 'lib/notification.rb', line 187

def reason_code
  params['reason_code']
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



115
116
117
# File 'lib/notification.rb', line 115

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

#statusObject

Whats the status of this transaction?



120
121
122
# File 'lib/notification.rb', line 120

def status
  params['payment_status']
end

#test?Boolean

This is the invocie which you passed to paypal

Returns:

  • (Boolean)


172
173
174
# File 'lib/notification.rb', line 172

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

#transaction_idObject

Id of this transaction (paypal number)



125
126
127
# File 'lib/notification.rb', line 125

def transaction_id
  params['txn_id']
end

#typeObject

What type of transaction are we dealing with?

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


131
132
133
# File 'lib/notification.rb', line 131

def type
  params['txn_type']
end