vaulted_billing 1.1.6 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
|
|
1
|
+
module VaultedBilling
|
2
|
+
module Gateways
|
3
|
+
class Bogus
|
4
|
+
module Failure
|
5
|
+
FailureCards = %w(4222222222222)
|
6
|
+
FailureMessages = [
|
7
|
+
'This transaction has been declined.',
|
8
|
+
'This transaction has been approved.',
|
9
|
+
'This transaction has been declined.',
|
10
|
+
'This transaction has been declined.',
|
11
|
+
'This transaction has been declined.',
|
12
|
+
'A valid amount is required.',
|
13
|
+
'The credit card number is invalid.',
|
14
|
+
'The credit card expiration date is invalid',
|
15
|
+
'The credit card has expired.',
|
16
|
+
'The ABA code is invalid',
|
17
|
+
'The account number is invalid.',
|
18
|
+
'A duplicate transaction has been submitted.',
|
19
|
+
]
|
20
|
+
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
|
25
|
+
def error_code_for(credit_card, amount)
|
26
|
+
amount.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def failure_message_for(credit_card, amount)
|
30
|
+
FailureMessages[error_code_for(credit_card, amount)] || FailureMessages.first
|
31
|
+
end
|
32
|
+
|
33
|
+
def success?(credit_card, amount)
|
34
|
+
credit_card.nil? || !failure?(credit_card, amount)
|
35
|
+
end
|
36
|
+
|
37
|
+
def failure?(credit_card, amount)
|
38
|
+
!credit_card.nil? && FailureCards.include?(credit_card.card_number)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -5,15 +5,49 @@ module VaultedBilling
|
|
5
5
|
##
|
6
6
|
# The Bogus gateway should only be used for simple interface testing
|
7
7
|
# to the VaultedBilling library. All customer and credit card requests
|
8
|
-
# will always return successfully.
|
9
|
-
# authorize, capture, etc.) will always return successfully
|
8
|
+
# will always return successfully. All transaction requests (purchase,
|
9
|
+
# authorize, capture, etc.) will always return successfully, unless a
|
10
|
+
# failure credit card number is given.
|
11
|
+
#
|
12
|
+
# If a failure credit card number is given, then the transaction amount is
|
13
|
+
# used to determine the error message and code to return.
|
10
14
|
#
|
11
15
|
# The primary purpose of this gateway is to provide you with an end
|
12
16
|
# point for testing your interface, as well as a fairly reasonable
|
13
17
|
# gateway for performing simple, non-network based tests against.
|
14
18
|
#
|
19
|
+
# To test failure messages, use the credit card number '4222222222222'.
|
20
|
+
# This card number will trigger failed transaction responses from the
|
21
|
+
# Bogus gateway for purchase and authorize requests. In order to receive a
|
22
|
+
# specific error message / code, set the transaction amount to one of the
|
23
|
+
# following:
|
24
|
+
#
|
25
|
+
# 0: 'This transaction has been declined.'
|
26
|
+
# 1: 'This transaction has been approved.'
|
27
|
+
# 2: 'This transaction has been declined.'
|
28
|
+
# 3: 'This transaction has been declined.'
|
29
|
+
# 4: 'This transaction has been declined.'
|
30
|
+
# 5: 'A valid amount is required.'
|
31
|
+
# 6: 'The credit card number is invalid.'
|
32
|
+
# 7: 'The credit card expiration date is invalid'
|
33
|
+
# 8: 'The credit card has expired.'
|
34
|
+
# 9: 'The ABA code is invalid'
|
35
|
+
# 10: 'The account number is invalid.'
|
36
|
+
# 11: 'A duplicate transaction has been submitted.'
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# customer = Customer.new(...)
|
41
|
+
# credit_card = CreditCard.new(:card_number => '4222222222222')
|
42
|
+
# bogus.purchase(customer, credit_card, 6.00)
|
43
|
+
# # => Failed transaction, 'The credit card number is invalid.'
|
44
|
+
#
|
15
45
|
class Bogus
|
46
|
+
autoload :Failure, 'vaulted_billing/gateways/bogus/failure'
|
47
|
+
|
16
48
|
include VaultedBilling::Gateway
|
49
|
+
include VaultedBilling::Gateways::Bogus::Failure
|
50
|
+
|
17
51
|
|
18
52
|
def initialize(options = {})
|
19
53
|
end
|
@@ -43,23 +77,23 @@ module VaultedBilling
|
|
43
77
|
end
|
44
78
|
|
45
79
|
def authorize(customer, credit_card, amount, options = {})
|
46
|
-
transaction_response
|
80
|
+
transaction_response credit_card, amount
|
47
81
|
end
|
48
82
|
|
49
83
|
def purchase(customer, credit_card, amount, options = {})
|
50
|
-
transaction_response
|
84
|
+
transaction_response credit_card, amount
|
51
85
|
end
|
52
86
|
|
53
87
|
def void(transaction_id, options = {})
|
54
|
-
transaction_response
|
88
|
+
transaction_response nil, nil
|
55
89
|
end
|
56
90
|
|
57
91
|
def capture(transaction_id, amount, options = {})
|
58
|
-
transaction_response
|
92
|
+
transaction_response nil, amount
|
59
93
|
end
|
60
94
|
|
61
95
|
def refund(transaction_id, amount, options = {})
|
62
|
-
transaction_response
|
96
|
+
transaction_response nil, amount
|
63
97
|
end
|
64
98
|
|
65
99
|
|
@@ -70,13 +104,22 @@ module VaultedBilling
|
|
70
104
|
Digest::MD5.hexdigest("--#{Time.now.to_f}--#{rand(1_000_000)}--#{rand(1_000_000)}--")
|
71
105
|
end
|
72
106
|
|
73
|
-
def transaction_response
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
107
|
+
def transaction_response(credit_card, amount)
|
108
|
+
attributes = { :id => new_identifier }
|
109
|
+
attributes[:masked_card_number] = "XXXX%04d" % [credit_card ? credit_card.card_number.to_s[-4..-1].to_i : rand(9999)]
|
110
|
+
success = true
|
111
|
+
error_code = nil
|
112
|
+
|
113
|
+
if success?(credit_card, amount)
|
114
|
+
attributes[:authcode] = new_identifier[0..5]
|
115
|
+
else
|
116
|
+
success = false
|
117
|
+
attributes[:message] = failure_message_for(credit_card, amount)
|
118
|
+
error_code = error_code_for(credit_card, amount)
|
119
|
+
end
|
120
|
+
|
121
|
+
respond_with VaultedBilling::Transaction.new(attributes), :success => success, :error_code => error_code
|
79
122
|
end
|
80
123
|
end
|
81
124
|
end
|
82
|
-
end
|
125
|
+
end
|
@@ -17,6 +17,11 @@ module VaultedBilling
|
|
17
17
|
#
|
18
18
|
class Ipcommerce
|
19
19
|
include VaultedBilling::Gateway
|
20
|
+
|
21
|
+
AvsResults = [
|
22
|
+
"Not Set", "Not Included", "Match", "No Match", "Issuer Not Certified",
|
23
|
+
"No Response From Card Association", "Unknown Response From Card Association", "Not Verified", "Bad Format"
|
24
|
+
]
|
20
25
|
|
21
26
|
Countries = %w(
|
22
27
|
!! AF AX AL DZ AS AD AO AI AQ
|
@@ -44,7 +49,7 @@ module VaultedBilling
|
|
44
49
|
TG TK TP TO TT TN TR TM TC TV
|
45
50
|
UG UA AE GB US UM UY UZ VU VE
|
46
51
|
VN VG VI WF EH YE YU ZM ZW
|
47
|
-
)
|
52
|
+
).freeze
|
48
53
|
|
49
54
|
Companies = {
|
50
55
|
2 => /^4\d{12}(\d{3})?$/, # Visa
|
@@ -54,6 +59,12 @@ module VaultedBilling
|
|
54
59
|
6 => /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/, # Discover
|
55
60
|
7 => /^35(28|29|[3-8]\d)\d{12}$/ # JCB
|
56
61
|
}.freeze
|
62
|
+
|
63
|
+
CVResults = [
|
64
|
+
"Not Set", "Match", "No Match", "Not Processed", "Not Included",
|
65
|
+
"No Code Present", "Should Have Been Present", "Issuer Not Certified", "Invalid", "No Response",
|
66
|
+
"Not Applicable"
|
67
|
+
].freeze
|
57
68
|
|
58
69
|
Endpoints = [
|
59
70
|
"https://cws-01.ipcommerce.com/REST/2.0.15/",
|
@@ -325,32 +336,28 @@ module VaultedBilling
|
|
325
336
|
|
326
337
|
def card_data(credit_card)
|
327
338
|
return nil if credit_card.nil?
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
:CVData => credit_card.cvv_number
|
351
|
-
}.select { |k, v| !v.nil? }
|
352
|
-
}
|
353
|
-
end
|
339
|
+
{
|
340
|
+
'PaymentAccountDataToken' => credit_card.vault_id,
|
341
|
+
'CardData' => {
|
342
|
+
'CardholderName' => credit_card.name_on_card.blank? ? nil : credit_card.name_on_card,
|
343
|
+
'CardType' => self.class.credit_card_type_id(credit_card.card_number),
|
344
|
+
'Expire' => credit_card.expires_on.try(:strftime, "%m%y"),
|
345
|
+
'PAN' => credit_card.vault_id ? ("XXXXXXXXXXX%04d" % [credit_card.card_number[-4..-1]]) : credit_card.card_number
|
346
|
+
},
|
347
|
+
'CardSecurityData' => {
|
348
|
+
'AVSData' => {
|
349
|
+
'CardholderName' => credit_card.name_on_card.blank? ? nil : credit_card.name_on_card,
|
350
|
+
'Street' => credit_card.street_address.try(:[], (0...20)),
|
351
|
+
'City' => credit_card.locality,
|
352
|
+
'StateProvince' => credit_card.region,
|
353
|
+
'PostalCode' => credit_card.postal_code.try(:gsub, /[^[:alnum:]]/, '').try(:[], (0...8)),
|
354
|
+
'Country' => credit_card.country.try(:to_ipcommerce_id),
|
355
|
+
'Phone' => credit_card.phone
|
356
|
+
}.select { |k, v| !v.nil? },
|
357
|
+
'CVDataProvided' => credit_card.cvv_number.nil? ? nil : 2,
|
358
|
+
'CVData' => credit_card.cvv_number
|
359
|
+
}.select { |k, v| v.is_a?(Hash) ? !v.empty? : !v.nil? }
|
360
|
+
}.select { |k, v| !v.nil? }
|
354
361
|
end
|
355
362
|
|
356
363
|
private
|
@@ -411,8 +418,8 @@ module VaultedBilling
|
|
411
418
|
if response.success?
|
412
419
|
Transaction.new({
|
413
420
|
:id => response.body['TransactionId'],
|
414
|
-
:avs_response => response.body['AVSResult']
|
415
|
-
:cvv_response => response.body['CVResult']
|
421
|
+
:avs_response => parse_avs_result(response.body['AVSResult']),
|
422
|
+
:cvv_response => parse_cvv_result(response.body['CVResult']),
|
416
423
|
:authcode => response.body['ApprovalCode'],
|
417
424
|
:message => response.body['StatusMessage'],
|
418
425
|
:code => response.body['Status'],
|
@@ -433,6 +440,25 @@ module VaultedBilling
|
|
433
440
|
end
|
434
441
|
end
|
435
442
|
|
443
|
+
def parse_avs_result(result)
|
444
|
+
return nil unless result
|
445
|
+
{
|
446
|
+
:result => result['ActualResult'],
|
447
|
+
:address => AvsResults[result['AddressResult']],
|
448
|
+
:country => AvsResults[result['CountryResult']],
|
449
|
+
:state => AvsResults[result['StateResult']],
|
450
|
+
:postal_code => AvsResults[result['PostalCodeResult']],
|
451
|
+
:phone => AvsResults[result['PhoneResult']],
|
452
|
+
:cardholder_name => AvsResults[result['CardholderNameResult']],
|
453
|
+
:city => AvsResults[result['CityResult']]
|
454
|
+
}
|
455
|
+
end
|
456
|
+
|
457
|
+
def parse_cvv_result(result)
|
458
|
+
return nil unless result
|
459
|
+
CVResults[result]
|
460
|
+
end
|
461
|
+
|
436
462
|
def parse_validation_errors(response)
|
437
463
|
errors = ChainableHash.new.merge(response.body || {})
|
438
464
|
if errors['ErrorResponse']['ValidationErrors'].present?
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module VaultedBilling
|
2
2
|
module Gateways
|
3
|
-
Dir[File.expand_path(File.join(File.dirname(__FILE__), 'gateways', '
|
3
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__), 'gateways', '*.rb'))].each do |file|
|
4
4
|
filename = File.basename(file, '.rb')
|
5
5
|
gateway_class = filename.camelize
|
6
6
|
autoload gateway_class, file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vaulted_billing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &2165677980 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.3'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2165677980
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: builder
|
27
|
-
requirement: &
|
27
|
+
requirement: &2165677480 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 2.1.2
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2165677480
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: multi_json
|
38
|
-
requirement: &
|
38
|
+
requirement: &2165677000 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2165677000
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: multi_xml
|
49
|
-
requirement: &
|
49
|
+
requirement: &2165676400 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.3.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2165676400
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: countries
|
60
|
-
requirement: &
|
60
|
+
requirement: &2165675960 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2165675960
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &2165675180 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '2.4'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2165675180
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: vcr
|
82
|
-
requirement: &
|
82
|
+
requirement: &2165674380 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '1.7'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *2165674380
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: webmock
|
93
|
-
requirement: &
|
93
|
+
requirement: &2165673920 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ~>
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '1.6'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *2165673920
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: factory_girl
|
104
|
-
requirement: &
|
104
|
+
requirement: &2165667440 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '1.3'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *2165667440
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: faker
|
115
|
-
requirement: &
|
115
|
+
requirement: &2165666980 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ~>
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0.9'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *2165666980
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: rake
|
126
|
-
requirement: &
|
126
|
+
requirement: &2165666520 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ~>
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0.9'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *2165666520
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: watchr
|
137
|
-
requirement: &
|
137
|
+
requirement: &2165666100 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :development
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *2165666100
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: open4
|
148
|
-
requirement: &
|
148
|
+
requirement: &2165665620 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ! '>='
|
@@ -153,10 +153,10 @@ dependencies:
|
|
153
153
|
version: '0'
|
154
154
|
type: :development
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *2165665620
|
157
157
|
- !ruby/object:Gem::Dependency
|
158
158
|
name: appraisal
|
159
|
-
requirement: &
|
159
|
+
requirement: &2165665200 !ruby/object:Gem::Requirement
|
160
160
|
none: false
|
161
161
|
requirements:
|
162
162
|
- - ! '>='
|
@@ -164,7 +164,7 @@ dependencies:
|
|
164
164
|
version: '0'
|
165
165
|
type: :development
|
166
166
|
prerelease: false
|
167
|
-
version_requirements: *
|
167
|
+
version_requirements: *2165665200
|
168
168
|
description: Several card processors and gateways support offloading the storage of
|
169
169
|
credit card information onto their service. This offloads PCI compliance to the
|
170
170
|
gateway rather than keeping it with each retailer. This library abstracts the interface
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- lib/vaulted_billing/errors.rb
|
185
185
|
- lib/vaulted_billing/gateway.rb
|
186
186
|
- lib/vaulted_billing/gateways/authorize_net_cim.rb
|
187
|
+
- lib/vaulted_billing/gateways/bogus/failure.rb
|
187
188
|
- lib/vaulted_billing/gateways/bogus.rb
|
188
189
|
- lib/vaulted_billing/gateways/ipcommerce.rb
|
189
190
|
- lib/vaulted_billing/gateways/nmi_customer_vault.rb
|