ruby-paypal 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|