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 +5 -1
- data/lib/ruby-paypal.rb +2 -1
- data/lib/ruby-paypal/credit_card_checks.rb +58 -0
- data/lib/ruby-paypal/paypal.rb +195 -10
- data/test/ts_ruby-paypal.rb +22 -8
- metadata +4 -3
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
@@ -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
|
data/lib/ruby-paypal/paypal.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
66
|
-
|
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
|
-
|
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
|
-
|
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|
|
data/test/ts_ruby-paypal.rb
CHANGED
@@ -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
|
-
|
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.
|
7
|
-
date:
|
8
|
-
summary:
|
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
|