ruby-paypal 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -42,7 +42,11 @@ DoDirectPayment APIs:
42
42
  # do your thing
43
43
  end
44
44
 
45
- The above code is for a final sale only
45
+ The above code is for a final sale only.
46
+
47
+ Note that the credit card number is checked against a modulo-10 algorithm (Luhn check) as well as a simple credit card
48
+ type check. For more information please refer to http://en.wikipedia.org/wiki/Luhn_algorithm and
49
+ http://en.wikipedia.org/wiki/Credit_card_number
46
50
 
47
51
  2. For the Express Checkout using the customer's PayPal account for payment, you will need to use the ExpressCheckout APIs:
48
52
 
data/lib/ruby-paypal.rb CHANGED
@@ -2,4 +2,5 @@
2
2
  #
3
3
  # Ruby-PayPal is a lightweight wrapper around the PayPal NVP APIs
4
4
 
5
- require 'ruby-paypal/paypal'
5
+ require 'ruby-paypal/paypal'
6
+ require 'ruby-paypal/credit_card_checks'
@@ -0,0 +1,58 @@
1
+ #
2
+ # Performs a series of credit card number checks.
3
+ #
4
+ module CreditCardChecks
5
+ # Perform Luhn check on a credit card number. Refer to http://en.wikipedia.org/wiki/Luhn_algorithm
6
+ #
7
+ def luhn_check(number)
8
+ num = 0
9
+ number.length.times { |p|
10
+ position = number.length - p - 1
11
+ if position % 2 == 0 then
12
+ doubled = number[position,1].to_i * 2
13
+ if doubled > 9 then
14
+ num = num + doubled.to_s[0,1].to_i + doubled.to_s[1,1].to_i
15
+ else
16
+ num = num + doubled.to_i
17
+ end
18
+ else
19
+ num = num + number[position,1].to_i
20
+ end
21
+ }
22
+ if num.to_i % 10 == 0 then
23
+ return true
24
+ else
25
+ return false
26
+ end
27
+ end
28
+
29
+ # Perform checks on credit card numbers with reference to the length of the credit card number
30
+ # and the type of credit card. Refer to http://en.wikipedia.org/wiki/Credit_card_number
31
+ #
32
+ def card_type_check(type, number)
33
+ validity = false
34
+ case type.upcase
35
+ when "VISA"
36
+ validity = true if (number.length == 16 or number.length = 13) and number[0,1] == "4"
37
+ when "MASTERCARD"
38
+ validity = true if (number.length == 16) and (52..55).include?(number[0,2].to_i)
39
+ when "AMEX"
40
+ validity = true if (number.length == 16) and ['34', '37'].include?(number[0,2])
41
+ when "DISCOVER"
42
+ validity = true if (number.length == 16) and (number[0,2] == "65" or number[0,4] == "6011")
43
+ when "SWITCH"
44
+ # TODO checks for Switch cards
45
+ validity = true
46
+ when "SOLO"
47
+ # TODO checks for Solo cards
48
+ validity = true
49
+ else
50
+ raise "Invalid card type entered"
51
+ end
52
+
53
+ return validity
54
+ end
55
+
56
+
57
+
58
+ end
@@ -2,12 +2,16 @@ require 'pp'
2
2
  require 'net/http'
3
3
  require 'net/https'
4
4
  require 'uri'
5
+ require 'lib/ruby-paypal/credit_card_checks'
5
6
 
6
7
  SANDBOX_SERVER = 'api-3t.sandbox.paypal.com/nvp'
7
- LIVE_SERVER = 'api-3t.paypal.com/nvp'
8
+ PRODUCTION_SERVER = 'api-3t.paypal.com/nvp'
8
9
  API_VERSION = '3.2'
9
10
 
10
11
  module Net
12
+ #
13
+ # A convenience class to enable this library to call PayPal's HTTPS NVP APIs
14
+ #
11
15
  class HTTPS < HTTP
12
16
  def initialize(address, port = nil, verify = :no_verify)
13
17
  super(address, port)
@@ -17,6 +21,23 @@ module Net
17
21
  end
18
22
  end
19
23
 
24
+ #
25
+ # A container for the response from PayPal. Each call to PayPal returns a generic set
26
+ # of information as well as a specific set for the call. For more information please refer
27
+ # to PayPal NVP API Developer Guide and Reference.
28
+ #
29
+ # To use retrieve information in the response, call the corresponding name of the object. For
30
+ # example, all responses from PayPal includes the field <tt>ACK</tt>. To get the data for this
31
+ # field:
32
+ #
33
+ #
34
+ # if response.ack == 'Success' then
35
+ # # do your stuff
36
+ # end
37
+ #
38
+ # This is because this class uses a meta-programming trick with method_missing to redirect all
39
+ # known method calls to its internal hash data structure.
40
+ #
20
41
  class PayPalResponse < Hash
21
42
  def method_missing(m,*a)
22
43
  if m.to_s.upcase =~ /=$/
@@ -29,27 +50,117 @@ class PayPalResponse < Hash
29
50
  end
30
51
  end
31
52
 
53
+
54
+ =begin rdoc
55
+ Author:: Chang Sau Sheong (mailto:sausheong.chang@gmail.com)
56
+ Copyright:: Copyright (c) 2007 Chang Sau Sheong
57
+ License:: Distributes under the same terms as Ruby
58
+ Version:: 0.0.2
59
+
60
+ =Installing Ruby-PayPal
61
+ A lightweight ruby wrapper for PayPal NVP APIs. To install type the following
62
+ at the command line:
63
+
64
+ $ gem install ruby-paypal
65
+
66
+
67
+ =Using Ruby-PayPal
68
+ It's critical that you understand how PayPal works and how the PayPal NVP API
69
+ works. You should be relatively well-versed in the NVP API Developer Guide and
70
+ Reference (https://www.paypal.com/en_US/ebook/PP_NVPAPI_DeveloperGuide/index.html).
71
+ You should also visit and register yourself with the PayPal Developer Network
72
+ and get a Sandbox account with in the PayPal Development Central
73
+ (https://developer.paypal.com/).
74
+
75
+ Note that this library only supports the API signature method of securing the API credentials.
76
+
77
+ ==Direct Payment
78
+ To use credit card payment through PayPal, you need to use the DoDirectPayment APIs:
79
+
80
+ username = <PayPal API username>
81
+ password = <PayPal API password>
82
+ signature = <PayPal API signature>
83
+
84
+ ipaddress = '192.168.1.1' # can be any IP address
85
+ amount = '100.00' # amount paid
86
+ card_type = 'VISA' # can be Visa, Mastercard, Amex etc
87
+ card_no = '4512345678901234' # credit card number
88
+ exp_date = '022010' # expiry date of the credit card
89
+ first_name = 'Sau Sheong'
90
+ last_name = 'Chang'
91
+
92
+ paypal = Paypal.new(username, password, signature) # uses the PayPal sandbox
93
+ response = paypal.do_direct_payment_sale(ipaddress, amount, card_type,
94
+ card_no, exp_date, first_name, last_name)
95
+ if response.ack == 'Success' then
96
+ # do your thing
97
+ end
98
+
99
+ The above code is for a final sale only.
100
+
101
+ Note that the credit card number is checked against a modulo-10 algorithm (Luhn check) as well as a simple credit card
102
+ type check. For more information please refer to http://en.wikipedia.org/wiki/Luhn_algorithm and
103
+ http://en.wikipedia.org/wiki/Credit_card_number
104
+
105
+ ==Express Checkout
106
+ To use the customer's PayPal account for payment, you will need to use the ExpressCheckout APIs:
107
+
108
+ <to be documented>
109
+
110
+ =More information
111
+ I will be continually providing updates in my blog at http://blog.saush.com
112
+
113
+ =end
114
+
32
115
  class Paypal
33
- def initialize(user, password, signature, url=SANDBOX_SERVER, subject=nil)
116
+ include CreditCardChecks
117
+
118
+ # Create a new object with the given user name, password and signature. To enable production
119
+ # access to PayPal change the url to the live PayPal server. Set url to <tt>:production</tt> to change
120
+ # access to PayPal production servers.
121
+ #
122
+ def initialize(user, password, signature, url=:sandbox, subject=nil)
34
123
  @api_parameters = {'USER' => user,
35
124
  'PWD' => password,
36
125
  'VERSION' => API_VERSION,
37
126
  'SIGNATURE' => signature }
38
- @paypal_url = url
127
+ if url == :sandbox
128
+ @paypal_url = SANDBOX_SERVER
129
+ elsif url == :production
130
+ @paypal_url = PRODUCTION_SERVER
131
+ else
132
+ raise 'Invalid url specified'
133
+ end
39
134
  end
40
135
 
136
+ # Performs credit card payment with PayPal, but only requesting for authorization. You need
137
+ # to capture the funds later. Calls do_direct_payment.
138
+ #
139
+ # Equivalent of DoDirectPayment with the PAYMENTACTION of 'authorization'
140
+ #
41
141
  def do_direct_payment_authorization(ipaddress, amount, credit_card_type, credit_card_no, expiry_date,
42
142
  first_name, last_name, cvv2=nil, other_params={})
43
143
  do_direct_payment('Authorization', ipaddress, amount, credit_card_type, credit_card_no,
44
144
  expiry_date, first_name, last_name, cvv2, other_params)
45
145
  end
46
146
 
147
+ # Performs credit card payment with PayPal, finalizing the sale. Funds are captured immediately.
148
+ # Calls do_direct_payment.
149
+ #
150
+ # Equivalent of DoDirectPayment with the PAYMENTACTION of 'sale'
151
+ #
47
152
  def do_direct_payment_sale(ipaddress, amount, credit_card_type, credit_card_no, expiry_date,
48
153
  first_name, last_name, cvv2=nil, other_params={})
49
154
  do_direct_payment('Sale', ipaddress, amount, credit_card_type, credit_card_no,
50
155
  expiry_date, first_name, last_name, cvv2, other_params)
51
156
  end
52
157
 
158
+ # Performs credit card payment with PayPal.
159
+ #
160
+ # Equivalent of DoDirectPayment.
161
+ #
162
+ # Performs Luhn check and a simple credit card type check based on the card number.
163
+ #
53
164
  def do_direct_payment(payment_action, ipaddress, amount, credit_card_type,
54
165
  credit_card_no, expiry_date, first_name, last_name, cvv2=nil, other_params={})
55
166
  params = {
@@ -62,12 +173,19 @@ class Paypal
62
173
  'FIRSTNAME' => first_name,
63
174
  'LASTNAME' => last_name,
64
175
  'IPADDRESS' => ipaddress }
65
- params['CVV2'] = cvv2 unless cvv2.nil?
66
- params.merge! other_params
67
- make_nvp_call(params)
68
- end
176
+ params['CVV2'] = cvv2 unless cvv2.nil?
177
+ params.merge! other_params
69
178
 
179
+ raise 'Invalid credit card number' if not luhn_check(params['ACCT'])
180
+ raise 'Invalid credit card type' if not card_type_check(params['CREDITCARDTYPE'], params['ACCT'])
70
181
 
182
+ make_nvp_call(params)
183
+ end
184
+
185
+ # Performs payment through PayPal.
186
+ #
187
+ # Equivalent of SetExpressCheckout.
188
+ #
71
189
  def set_express_checkout(return_url, cancel_url, amount)
72
190
  params = {
73
191
  'METHOD' => 'SetExpressCheckout',
@@ -78,6 +196,10 @@ class Paypal
78
196
  make_nvp_call(params)
79
197
  end
80
198
 
199
+ # Gets the details of the request started through set_express_checkout.
200
+ #
201
+ # Equivalent of GetExpressCheckoutDetails.
202
+ #
81
203
  def get_express_checkout_details(token)
82
204
  params = {
83
205
  'METHOD' => 'GetExpressCheckoutDetails',
@@ -86,6 +208,11 @@ class Paypal
86
208
  make_nvp_call(params)
87
209
  end
88
210
 
211
+ #
212
+ # Gets payment through PayPal for Express Checkout.
213
+ #
214
+ # Equivalent of DoExpressCheckoutPayment
215
+ #
89
216
  def do_express_checkout_payment(token, payment_action,payer_id, amount)
90
217
  params = {
91
218
  'METHOD' => 'DoExpressCheckoutPayment',
@@ -97,16 +224,63 @@ class Paypal
97
224
  make_nvp_call(params)
98
225
  end
99
226
 
100
- def do_authorization(transaction_id, amount)
227
+ #
228
+ # Does authorization of a request.
229
+ #
230
+ # Equivalent of DoAuthorization.
231
+ #
232
+ def do_authorization(transaction_id, amount, currency_code = 'USD')
101
233
  params = {
102
234
  'METHOD' => 'DoAuthorization',
103
235
  'TRANSACTIONID' => transaction_id,
104
236
  'AMT' => amount.to_s,
105
- 'TRANSACTIONENTITY' => 'Order'
237
+ 'TRANSACTIONENTITY' => 'Order',
238
+ 'CURRENCYCODE' => currency_code
106
239
  }
107
240
  make_nvp_call(params)
108
241
  end
109
242
 
243
+ #
244
+ # Captures payment for a transaction.
245
+ #
246
+ # Equivalent of DoCapture.
247
+ #
248
+ def do_capture(authorization_id, amount, complete=true, currency_code='USD', invoice_no=nil, note=nil, soft_descriptor=nil)
249
+ params = {
250
+ 'METHOD' => 'DoCapture',
251
+ 'AUTHORIZATIONID' => authorization_id,
252
+ 'AMT' => amount.to_s,
253
+ 'CURRENCYCODE' => currency_code
254
+ }
255
+ if complete then
256
+ params['COMPLETETYPE'] = 'Complete'
257
+ else
258
+ params['COMPLETETYPE'] = 'NotComplete'
259
+ end
260
+ params['INVNUM'] = invoice_no unless invoice_no.nil?
261
+ params['NOTE'] = note unless note.nil?
262
+ params['SOFTDESCRIPTOR'] = soft_descriptor unless soft_descriptor.nil?
263
+ make_nvp_call(params)
264
+ end
265
+
266
+ #
267
+ # Re-authorizes an authorized transaction.
268
+ #
269
+ # Equivalent of DoReauthorization.
270
+ #
271
+ def do_reauthorization(authorization_id, amount, currency_code = 'USD')
272
+ params = {
273
+ 'METHOD' => 'DoReauthorization',
274
+ 'AUTHORIZATIONID' => authorization_id,
275
+ 'AMT' => amount.to_s,
276
+ 'CURRENCYCODE' => currency_code
277
+ }
278
+ make_nvp_call(params)
279
+ end
280
+
281
+ #
282
+ # Makes the call to the PayPal NVP API. This is the workhorse method for the other method calls.
283
+ #
110
284
  def make_nvp_call(params)
111
285
  @api_parameters.merge! params
112
286
  parameters = URI.escape(@api_parameters.to_a.collect {|pair| pair.join('=')}.join('&'))
@@ -115,9 +289,20 @@ class Paypal
115
289
  PayPalResponse.new.merge get_hash(response.body)
116
290
  end
117
291
 
118
- private
292
+ #
293
+ # Checks and returns information on the card based on the given BIN (Bank Identification Number).
294
+ # Currently inactive since bindatabase.com is down.
295
+ #
296
+ def bin_check(bin)
297
+ # stub for check to bindatabase.com, currently down
298
+ end
119
299
 
300
+ private
120
301
 
302
+ #
303
+ # Gets a hash from a string, with a set of name value pairs joined by '='
304
+ # and concatenated with '&'
305
+ #
121
306
  def get_hash(string)
122
307
  hash = {}
123
308
  string.split('&').collect { |pair| pair.split('=') }.each { |a|
@@ -1,20 +1,34 @@
1
- require 'rubygems'
2
1
  require 'pp'
3
- require 'ruby-paypal'
4
2
  require 'test/unit'
3
+ require 'lib/ruby-paypal/paypal'
4
+ require 'lib/ruby-paypal/credit_card_checks'
5
+
5
6
 
6
7
  class RubyPayPal < Test::Unit::TestCase
8
+ def setup
9
+ @test_data = {"visa" => "4154727623381301", "visa" => "4015262522324137", "visa" => "4574806205610007"}
10
+ @paypal = Paypal.new('css.pa_1195828529_biz_api1.gmail.com', '1195828547', 'AJsoTDMhNESFz43L9WKtkP2tVCZZAZ3Wl.IxVLj8IfJQsjg8WZYMENpS')
11
+ end
7
12
  def test_do_direct_payment_sale
8
- paypal = Paypal.new('css.pa_1195828529_biz_api1.gmail.com', '1195828547',
9
- 'AJsoTDMhNESFz43L9WKtkP2tVCZZAZ3Wl.IxVLj8IfJQsjg8WZYMENpS')
10
- resp = paypal.do_direct_payment_sale('202.156.13.1', '14.34', 'VISA',
11
- '4574806205610007', '022017', 'Test', 'User')
13
+ resp = @paypal.do_direct_payment_sale('202.156.13.1', '14.34', 'visa', '4574806205610007', '022017', 'Test', 'User')
12
14
  assert_equal("Success", resp.ack)
13
15
  end
16
+
17
+ def test_luhn_check
18
+ @test_data.each { |type, number|
19
+ assert_equal(@paypal.luhn_check(number), true)
20
+ }
21
+ end
14
22
 
23
+ def test_card_type_check
24
+ @test_data.each { |type, number|
25
+ assert_equal(@paypal.card_type_check(type,number), true)
26
+ }
27
+ end
28
+
15
29
  def test_do_direct_payment_authorization
16
-
30
+
17
31
  end
18
-
32
+
19
33
  end
20
34
 
metadata CHANGED
@@ -3,9 +3,9 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: ruby-paypal
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.1
7
- date: 2007-12-23 00:00:00 +08:00
8
- summary: An lightweight Ruby wrapper for PayPal NVP API
6
+ version: 0.0.2
7
+ date: 2008-01-02 00:00:00 +08:00
8
+ summary: A lightweight Ruby wrapper for PayPal NVP API
9
9
  require_paths:
10
10
  - lib
11
11
  email: sausheong.chang@gmail.com
@@ -30,6 +30,7 @@ authors:
30
30
  - Chang Sau Sheong
31
31
  files:
32
32
  - lib/ruby-paypal
33
+ - lib/ruby-paypal/credit_card_checks.rb
33
34
  - lib/ruby-paypal/paypal.rb
34
35
  - lib/ruby-paypal.rb
35
36
  - test/ts_ruby-paypal.rb