vaulted_billing 1.1.0 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -4
- data/lib/vaulted_billing/credit_card.rb +30 -4
- data/lib/vaulted_billing/gateway.rb +5 -2
- data/lib/vaulted_billing/gateways/authorize_net_cim.rb +2 -2
- data/lib/vaulted_billing/gateways/bogus.rb +6 -6
- data/lib/vaulted_billing/gateways/ipcommerce.rb +113 -52
- data/lib/vaulted_billing/gateways/nmi_customer_vault.rb +2 -2
- data/lib/vaulted_billing/http.rb +1 -0
- data/lib/vaulted_billing/version.rb +1 -1
- metadata +39 -28
data/README.md
CHANGED
@@ -13,6 +13,7 @@ Since you only store identifiers on your end, you are only responsible for: 1) t
|
|
13
13
|
VaultedBilling supports the following payment providers:
|
14
14
|
|
15
15
|
* [Authorize.net Customer Information Manager][authorize-net-cim]
|
16
|
+
* [IP Commerce Tokenization][ipcommerce-tokenization]
|
16
17
|
* [Network Merchant Inc. Customer Vault][nmi-vault]
|
17
18
|
|
18
19
|
VaultedBilling also supports the following fictitious payment provider for testing purposes:
|
@@ -67,10 +68,6 @@ bogus.add_customer(customer).tap do |customer_response|
|
|
67
68
|
end
|
68
69
|
```
|
69
70
|
|
70
|
-
### Real world example
|
71
|
-
|
72
|
-
TODO: Real world example coming soon.
|
73
|
-
|
74
71
|
## Testing
|
75
72
|
|
76
73
|
When you're manually testing your application - meaning Development mode - it is often best to actually have a "sandbox" or "test" account with your payment processor. In this mode, you should use those credentials with VaultedBilling and indicate to VaultedBilling that the processor is in test mode, either by setting it in the VaultedBilling::Configuration (see Configuration) or when you instantiate your Gateway. You should note that all gateways, except for the Bogus gateway, attempt to open network connections when in use. So, if you are testing with them (which is suggested), you should look into an HTTP mocking library like [VCR][vcr] with [WebMock][webmock].
|
@@ -80,6 +77,7 @@ Strictly for testing interaction with the VaultedBilling library, there is a "Bo
|
|
80
77
|
[ci]: http://travis-ci.org/envylabs/vaulted_billing
|
81
78
|
[ci-image]: https://secure.travis-ci.org/envylabs/vaulted_billing.png
|
82
79
|
[authorize-net-cim]: http://www.authorize.net/solutions/merchantsolutions/merchantservices/cim/
|
80
|
+
[ipcommerce-tokenization]: http://developer.ipcommerce.com/developer/integration/value_added_capabilities.aspx
|
83
81
|
[nmi-vault]: https://www.nmi.com/newsmedia/index.php?ann_id=14
|
84
82
|
[bundler]: http://gembundler.com/
|
85
83
|
[vcr]: https://github.com/myronmarston/vcr
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'iso3166'
|
2
|
+
|
1
3
|
module VaultedBilling
|
2
4
|
##
|
3
5
|
# Intermediary class used to translate your local credit card information
|
@@ -15,8 +17,24 @@ module VaultedBilling
|
|
15
17
|
# the card is already stored on the gateway and is not new information.
|
16
18
|
#
|
17
19
|
class CreditCard
|
20
|
+
class Country < String
|
21
|
+
def to_iso_3166
|
22
|
+
country.number.to_i if country.data
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_ipcommerce_id
|
26
|
+
VaultedBilling::Gateways::Ipcommerce::Countries.index(self) || 0
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def country
|
32
|
+
ISO3166::Country.new(self)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
18
36
|
attr_accessor :card_number # The customer's credit card number
|
19
|
-
|
37
|
+
attr_reader :country # The country of the credit card address.
|
20
38
|
attr_accessor :currency # The currency used by the credit card.
|
21
39
|
attr_accessor :cvv_number # The verification number (CVV2) on the card.
|
22
40
|
attr_accessor :expires_on # The date on which the credit card expires.
|
@@ -41,9 +59,7 @@ module VaultedBilling
|
|
41
59
|
send("#{key}=", value) if respond_to?("#{key}=")
|
42
60
|
end
|
43
61
|
end
|
44
|
-
|
45
|
-
def to_vaulted_billing; self; end
|
46
|
-
|
62
|
+
|
47
63
|
def ==(o)
|
48
64
|
self.attributes == o.attributes
|
49
65
|
end
|
@@ -65,5 +81,15 @@ module VaultedBilling
|
|
65
81
|
:phone => phone
|
66
82
|
}
|
67
83
|
end
|
84
|
+
|
85
|
+
def country=(input)
|
86
|
+
@country = Country.new(input) if input
|
87
|
+
end
|
88
|
+
|
89
|
+
def name_on_card
|
90
|
+
[first_name, last_name].compact.join(" ")
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_vaulted_billing; self; end
|
68
94
|
end
|
69
95
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module VaultedBilling
|
2
2
|
module Gateway
|
3
3
|
module Response
|
4
|
+
attr_accessor :response
|
4
5
|
attr_accessor :raw_response
|
5
6
|
attr_accessor :response_message
|
6
7
|
attr_accessor :error_code
|
8
|
+
attr_accessor :transactions
|
7
9
|
attr_writer :connection_error
|
8
10
|
attr_writer :success
|
9
11
|
def success?; @success; end
|
@@ -22,11 +24,11 @@ module VaultedBilling
|
|
22
24
|
raise NotImplementedError
|
23
25
|
end
|
24
26
|
|
25
|
-
def add_customer_credit_card(customer, credit_card)
|
27
|
+
def add_customer_credit_card(customer, credit_card, options = {})
|
26
28
|
raise NotImplementedError
|
27
29
|
end
|
28
30
|
|
29
|
-
def update_customer_credit_card(customer, credit_card)
|
31
|
+
def update_customer_credit_card(customer, credit_card, options = {})
|
30
32
|
raise NotImplementedError
|
31
33
|
end
|
32
34
|
|
@@ -65,6 +67,7 @@ module VaultedBilling
|
|
65
67
|
o.raw_response = options[:raw_response] || ''
|
66
68
|
o.response_message = options[:response_message]
|
67
69
|
o.error_code = options[:error_code]
|
70
|
+
o.transactions = options[:transactions] || nil
|
68
71
|
yield(o) if block_given?
|
69
72
|
end
|
70
73
|
end
|
@@ -58,7 +58,7 @@ module VaultedBilling
|
|
58
58
|
respond_with(customer, result, :success => result.success?)
|
59
59
|
end
|
60
60
|
|
61
|
-
def add_customer_credit_card(customer, credit_card)
|
61
|
+
def add_customer_credit_card(customer, credit_card, options = {})
|
62
62
|
customer = customer.to_vaulted_billing
|
63
63
|
credit_card = credit_card.to_vaulted_billing
|
64
64
|
data = build_request('createCustomerPaymentProfileRequest') { |xml|
|
@@ -75,7 +75,7 @@ module VaultedBilling
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def update_customer_credit_card(customer, credit_card)
|
78
|
+
def update_customer_credit_card(customer, credit_card, options = {})
|
79
79
|
customer = customer.to_vaulted_billing
|
80
80
|
credit_card = credit_card.to_vaulted_billing
|
81
81
|
data = build_request('updateCustomerPaymentProfileRequest') { |xml|
|
@@ -30,11 +30,11 @@ module VaultedBilling
|
|
30
30
|
respond_with customer.to_vaulted_billing
|
31
31
|
end
|
32
32
|
|
33
|
-
def add_customer_credit_card(customer, credit_card)
|
33
|
+
def add_customer_credit_card(customer, credit_card, options = {})
|
34
34
|
respond_with(credit_card.to_vaulted_billing) { |c| c.vault_id = new_identifier }
|
35
35
|
end
|
36
36
|
|
37
|
-
def update_customer_credit_card(customer, credit_card)
|
37
|
+
def update_customer_credit_card(customer, credit_card, options = {})
|
38
38
|
respond_with credit_card.to_vaulted_billing
|
39
39
|
end
|
40
40
|
|
@@ -42,19 +42,19 @@ module VaultedBilling
|
|
42
42
|
respond_with credit_card.to_vaulted_billing
|
43
43
|
end
|
44
44
|
|
45
|
-
def authorize(customer, credit_card, amount)
|
45
|
+
def authorize(customer, credit_card, amount, options = {})
|
46
46
|
transaction_response
|
47
47
|
end
|
48
48
|
|
49
|
-
def purchase(customer, credit_card, amount)
|
49
|
+
def purchase(customer, credit_card, amount, options = {})
|
50
50
|
transaction_response
|
51
51
|
end
|
52
52
|
|
53
|
-
def void(transaction_id)
|
53
|
+
def void(transaction_id, options = {})
|
54
54
|
transaction_response
|
55
55
|
end
|
56
56
|
|
57
|
-
def capture(transaction_id, amount)
|
57
|
+
def capture(transaction_id, amount, options = {})
|
58
58
|
transaction_response
|
59
59
|
end
|
60
60
|
|
@@ -18,6 +18,34 @@ module VaultedBilling
|
|
18
18
|
class Ipcommerce
|
19
19
|
include VaultedBilling::Gateway
|
20
20
|
|
21
|
+
Countries = %w(
|
22
|
+
!! AF AX AL DZ AS AD AO AI AQ
|
23
|
+
AG AR AM AW AU AT AZ BS BH BD
|
24
|
+
BB BY BE BZ BJ BM BT BO BA BW
|
25
|
+
BV BR IO BN BG BF BI KH CM CA
|
26
|
+
CV KY CF TD CL CN CX CC CO KM
|
27
|
+
CG CD CK CR CI HR CU CY CZ DK
|
28
|
+
DJ DM DO EC EG SV GQ ER EE ET
|
29
|
+
FK FO FJ FI FR FX GF PF TF GA
|
30
|
+
GM GE DE GH GI GR GL GD GP GU
|
31
|
+
GT GG GN GW GY HT HM VA HN HK
|
32
|
+
HU IS IN ID IR IQ IE IM IL IT
|
33
|
+
JM JP JE JO KZ KE KI KP KR KW
|
34
|
+
KG LA LV LB LS LR LY LI LT LU
|
35
|
+
MO MK MG MW MY MV ML MT MH MQ
|
36
|
+
MR MU YT MX FM MD MC MN ME MS
|
37
|
+
MA MZ MM NA NR NP NL AN NC NZ
|
38
|
+
NI NE NG NU NF MP NO OM PK PW
|
39
|
+
PS PA PG PY PE PH PN PL PT PR
|
40
|
+
QA RE RO RU RW SH KN LC PM VC
|
41
|
+
WS SM ST SA SN RS CS SC SL SG
|
42
|
+
SK SI SB SO ZA GS ES LK SD SR
|
43
|
+
SJ SZ SE CH SY TW TJ TZ TH TL
|
44
|
+
TG TK TP TO TT TN TR TM TC TV
|
45
|
+
UG UA AE GB US UM UY UZ VU VE
|
46
|
+
VN VG VI WF EH YE YU ZM ZW
|
47
|
+
)
|
48
|
+
|
21
49
|
Companies = {
|
22
50
|
2 => /^4\d{12}(\d{3})?$/, # Visa
|
23
51
|
3 => /^(5[1-5]\d{4}|677189)\d{10}$/, # MasterCard
|
@@ -29,7 +57,7 @@ module VaultedBilling
|
|
29
57
|
|
30
58
|
class ServiceKeyStore
|
31
59
|
UnavailableKeyError = Class.new(VaultedBilling::CredentialError)
|
32
|
-
|
60
|
+
|
33
61
|
attr_reader :identity_token
|
34
62
|
|
35
63
|
def initialize(identity_token)
|
@@ -59,10 +87,12 @@ module VaultedBilling
|
|
59
87
|
end
|
60
88
|
|
61
89
|
def renew!
|
90
|
+
response = http.get
|
91
|
+
raise(UnavailableKeyError, 'Unable to renew service keys.') unless response.success?
|
62
92
|
@expires_at = Time.now + 30.minutes
|
63
|
-
@key =
|
93
|
+
@key = response.body.try(:[], 1...-1)
|
64
94
|
end
|
65
|
-
|
95
|
+
|
66
96
|
private
|
67
97
|
def http
|
68
98
|
@request ||= begin
|
@@ -101,15 +131,22 @@ module VaultedBilling
|
|
101
131
|
# A stub, since the IP Commerce only generates tokens during
|
102
132
|
# successful authorization transactions.
|
103
133
|
#
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
134
|
+
def add_customer_credit_card(customer, credit_card, options = {})
|
135
|
+
credit_card = credit_card.to_vaulted_billing
|
136
|
+
|
137
|
+
authorization = authorize(customer, credit_card, 1.00, options)
|
138
|
+
void = void(authorization.id, options) if authorization.success?
|
139
|
+
|
140
|
+
respond_with(credit_card, authorization.response, {
|
141
|
+
:success => authorization.success?,
|
142
|
+
:transactions => { :void => void, :authorization => authorization }
|
143
|
+
}) do |cc|
|
144
|
+
cc.vault_id = authorization.response.body['PaymentAccountDataToken'].presence
|
145
|
+
end
|
110
146
|
end
|
111
147
|
|
112
148
|
def authorize(customer, credit_card, amount, options = {})
|
149
|
+
credit_card = credit_card.to_vaulted_billing
|
113
150
|
data = {
|
114
151
|
"__type" => "AuthorizeTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Rest",
|
115
152
|
:ApplicationProfileId => @application_id,
|
@@ -118,31 +155,25 @@ module VaultedBilling
|
|
118
155
|
:"__type" => "BankcardTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Bankcard",
|
119
156
|
:TransactionData => {
|
120
157
|
:Amount => "%.2f" % amount,
|
158
|
+
:ApprovalCode => options[:approval_code],
|
121
159
|
:CurrencyCode => 4,
|
122
160
|
:TransactionDateTime => Time.now.xmlschema,
|
123
161
|
:CustomerPresent => 0,
|
124
|
-
:EntryMode => 1,
|
162
|
+
:EntryMode => options[:entry_mode] || 1, # 1 => keyed
|
125
163
|
:GoodsType => 0,
|
126
164
|
:IndustryType => 2,
|
127
165
|
:SignatureCaptured => false,
|
128
166
|
:OrderNumber => options[:order_id] || generate_order_number
|
129
167
|
},
|
130
|
-
:TenderData =>
|
131
|
-
:CardData => {
|
132
|
-
:CardholderName => nil,
|
133
|
-
:CardType => self.class.credit_card_type_id(credit_card.card_number),
|
134
|
-
:Expire => credit_card.expires_on.try(:strftime, "%m%y"),
|
135
|
-
:PAN => credit_card.card_number
|
136
|
-
}
|
137
|
-
}
|
168
|
+
:TenderData => card_data(credit_card)
|
138
169
|
}
|
139
170
|
}
|
140
|
-
|
171
|
+
|
141
172
|
response = http(options[:workflow_id] || @service_id).post(data)
|
142
|
-
transaction = new_transaction_from_response(response)
|
173
|
+
transaction = new_transaction_from_response(response)
|
143
174
|
respond_with(transaction,
|
144
175
|
response,
|
145
|
-
:success => (transaction.code
|
176
|
+
:success => valid_code?(transaction.code))
|
146
177
|
end
|
147
178
|
|
148
179
|
def capture(transaction_id, amount, options = {})
|
@@ -156,15 +187,16 @@ module VaultedBilling
|
|
156
187
|
:Amount => "%.2f" % amount
|
157
188
|
}
|
158
189
|
}
|
159
|
-
|
190
|
+
|
160
191
|
response = http(options[:workflow_id] || @service_id, transaction_id).put(data)
|
161
192
|
transaction = new_transaction_from_response(response)
|
162
193
|
respond_with(transaction,
|
163
194
|
response,
|
164
|
-
:success => (transaction.code
|
195
|
+
:success => valid_code?(transaction.code))
|
165
196
|
end
|
166
197
|
|
167
198
|
def purchase(customer, credit_card, amount, options = {})
|
199
|
+
credit_card = credit_card.try(:to_vaulted_billing)
|
168
200
|
data = {
|
169
201
|
"__type" => "AuthorizeAndCaptureTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Rest",
|
170
202
|
:ApplicationProfileId => @application_id,
|
@@ -173,31 +205,25 @@ module VaultedBilling
|
|
173
205
|
:"__type" => "BankcardTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Bankcard",
|
174
206
|
:TransactionData => {
|
175
207
|
:Amount => "%.2f" % amount,
|
208
|
+
:ApprovalCode => options[:approval_code],
|
176
209
|
:CurrencyCode => 4,
|
177
210
|
:TransactionDateTime => Time.now.xmlschema,
|
178
211
|
:CustomerPresent => 0,
|
179
212
|
:EmployeeId => options[:employee_id],
|
180
|
-
:EntryMode => 1,
|
213
|
+
:EntryMode => options[:entry_mode] || 1, # 1 => keyed
|
181
214
|
:GoodsType => 0,
|
182
215
|
:IndustryType => 2,
|
183
216
|
:OrderNumber => options[:order_id] || generate_order_number,
|
184
217
|
:SignatureCaptured => false
|
185
218
|
},
|
186
|
-
:TenderData =>
|
187
|
-
:CardData => {
|
188
|
-
:CardholderName => nil,
|
189
|
-
:CardType => self.class.credit_card_type_id(credit_card.card_number),
|
190
|
-
:Expire => credit_card.expires_on.try(:strftime, "%m%y"),
|
191
|
-
:PAN => credit_card.card_number
|
192
|
-
}
|
193
|
-
}
|
219
|
+
:TenderData => card_data(credit_card)
|
194
220
|
}
|
195
221
|
}
|
196
222
|
response = http(options[:workflow_id] || @service_id).post(data)
|
197
223
|
transaction = new_transaction_from_response(response)
|
198
224
|
respond_with(transaction,
|
199
225
|
response,
|
200
|
-
:success => (transaction.code
|
226
|
+
:success => valid_code?(transaction.code))
|
201
227
|
end
|
202
228
|
|
203
229
|
def refund(transaction_id, amount, options = {})
|
@@ -212,14 +238,14 @@ module VaultedBilling
|
|
212
238
|
:Amount => "%.2f" % amount
|
213
239
|
}
|
214
240
|
}
|
215
|
-
|
241
|
+
|
216
242
|
response = http(options[:workflow_id] || @service_id).post(data)
|
217
243
|
transaction = new_transaction_from_response(response)
|
218
244
|
respond_with(transaction,
|
219
245
|
response,
|
220
|
-
:success => (transaction.code
|
246
|
+
:success => valid_code?(transaction.code))
|
221
247
|
end
|
222
|
-
|
248
|
+
|
223
249
|
##
|
224
250
|
# A stub, since the IP Commerce only generates tokens during
|
225
251
|
# successful authorization transactions.
|
@@ -248,10 +274,10 @@ module VaultedBilling
|
|
248
274
|
# A stub, since the IP Commerce only generates tokens during
|
249
275
|
# successful authorization transactions.
|
250
276
|
#
|
251
|
-
def update_customer_credit_card(customer, credit_card)
|
252
|
-
|
277
|
+
def update_customer_credit_card(customer, credit_card, options = {})
|
278
|
+
add_customer_credit_card(customer, credit_card, options)
|
253
279
|
end
|
254
|
-
|
280
|
+
|
255
281
|
def void(transaction_id, options = {})
|
256
282
|
data = {
|
257
283
|
:"__type" => "Undo:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Rest",
|
@@ -267,9 +293,45 @@ module VaultedBilling
|
|
267
293
|
transaction = new_transaction_from_response(response)
|
268
294
|
respond_with(transaction,
|
269
295
|
response,
|
270
|
-
:success => (transaction.code
|
296
|
+
:success => valid_code?(transaction.code))
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
protected
|
301
|
+
|
302
|
+
def valid_code?(code)
|
303
|
+
[0,1].include?(code)
|
271
304
|
end
|
272
305
|
|
306
|
+
def card_data(credit_card)
|
307
|
+
return nil if credit_card.nil?
|
308
|
+
|
309
|
+
if credit_card.vault_id.present?
|
310
|
+
{ :PaymentAccountDataToken => credit_card.vault_id }
|
311
|
+
else
|
312
|
+
{
|
313
|
+
:CardData => {
|
314
|
+
:CardholderName => credit_card.name_on_card,
|
315
|
+
:CardType => self.class.credit_card_type_id(credit_card.card_number),
|
316
|
+
:Expire => credit_card.expires_on.try(:strftime, "%m%y"),
|
317
|
+
:PAN => credit_card.card_number
|
318
|
+
},
|
319
|
+
:CardSecurityData => {
|
320
|
+
:AVSData => {
|
321
|
+
:CardholderName => credit_card.name_on_card,
|
322
|
+
:Street => credit_card.street_address.try(:[], (0...20)),
|
323
|
+
:City => credit_card.locality,
|
324
|
+
:StateProvince => credit_card.region,
|
325
|
+
:PostalCode => credit_card.postal_code.try(:[], (0...5)),
|
326
|
+
:Country => credit_card.country.try(:to_ipcommerce_id),
|
327
|
+
:Phone => credit_card.phone
|
328
|
+
}.select { |k, v| !v.nil? },
|
329
|
+
:CVDataProvided => credit_card.cvv_number.nil? ? nil : 2,
|
330
|
+
:CVData => credit_card.cvv_number
|
331
|
+
}.select { |k, v| !v.nil? }
|
332
|
+
}
|
333
|
+
end
|
334
|
+
end
|
273
335
|
|
274
336
|
private
|
275
337
|
|
@@ -286,8 +348,7 @@ module VaultedBilling
|
|
286
348
|
end
|
287
349
|
return 1
|
288
350
|
end
|
289
|
-
|
290
|
-
|
351
|
+
|
291
352
|
def generate_order_number
|
292
353
|
(Time.now.to_f * 100000).to_i.to_s(36) + rand(60000000).to_s(36)
|
293
354
|
end
|
@@ -304,23 +365,22 @@ module VaultedBilling
|
|
304
365
|
:on_success => :on_success
|
305
366
|
})
|
306
367
|
end
|
307
|
-
|
368
|
+
|
308
369
|
def before_request(request)
|
309
370
|
request.body = MultiJson.encode(request.body)
|
310
|
-
# request.delete "accept"
|
311
371
|
end
|
312
|
-
|
372
|
+
|
313
373
|
def on_success(response)
|
314
374
|
response.body = decode_body(response.body) || {}
|
315
375
|
response.success = [1, 2].include?(response.body['Status'])
|
316
376
|
end
|
317
|
-
|
377
|
+
|
318
378
|
def decode_body(string)
|
319
379
|
MultiJson.decode(string)
|
320
380
|
rescue MultiJson::DecodeError
|
321
381
|
parse_error(string)
|
322
382
|
end
|
323
|
-
|
383
|
+
|
324
384
|
def new_transaction_from_response(response)
|
325
385
|
if response.success?
|
326
386
|
Transaction.new({
|
@@ -346,27 +406,28 @@ module VaultedBilling
|
|
346
406
|
end
|
347
407
|
end
|
348
408
|
end
|
349
|
-
|
409
|
+
|
350
410
|
def parse_validation_errors(response)
|
351
411
|
errors = ChainableHash.new.merge(response.body || {})
|
352
412
|
if errors['ErrorResponse']['ValidationErrors'].present?
|
353
413
|
[errors['ErrorResponse']['ValidationErrors']['ValidationError']].flatten.collect { |e| e['RuleMessage'] }
|
354
414
|
end
|
355
415
|
end
|
356
|
-
|
416
|
+
|
357
417
|
def parse_error(response_body)
|
358
418
|
MultiXml.parse(response_body)
|
359
419
|
rescue MultiXml::ParseError
|
360
420
|
end
|
361
|
-
|
421
|
+
|
362
422
|
def respond_with(object, response = nil, options = {}, &block)
|
363
423
|
super(object, options, &block).tap do |o|
|
364
424
|
if response
|
425
|
+
o.response = response
|
365
426
|
o.raw_response = response.raw_response.try(:body)
|
366
427
|
o.connection_error = response.connection_error
|
367
428
|
end
|
368
429
|
end
|
369
430
|
end
|
370
|
-
end
|
431
|
+
end
|
371
432
|
end
|
372
|
-
end
|
433
|
+
end
|
@@ -52,7 +52,7 @@ module VaultedBilling
|
|
52
52
|
respond_with customer.to_vaulted_billing
|
53
53
|
end
|
54
54
|
|
55
|
-
def add_customer_credit_card(customer, credit_card)
|
55
|
+
def add_customer_credit_card(customer, credit_card, options = {})
|
56
56
|
data = storage_data('add_customer', customer.to_vaulted_billing, credit_card.to_vaulted_billing)
|
57
57
|
response = http.post(data)
|
58
58
|
respond_with(credit_card, response, :success => response.success?) do |c|
|
@@ -60,7 +60,7 @@ module VaultedBilling
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
def update_customer_credit_card(customer, credit_card)
|
63
|
+
def update_customer_credit_card(customer, credit_card, options = {})
|
64
64
|
data = storage_data('update_customer', customer.to_vaulted_billing, credit_card.to_vaulted_billing)
|
65
65
|
response = http.post(data)
|
66
66
|
respond_with(credit_card, response, :success => response.success?)
|
data/lib/vaulted_billing/http.rb
CHANGED
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.1.
|
4
|
+
version: 1.1.2
|
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-08-
|
12
|
+
date: 2011-08-30 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &2153465380 !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: *2153465380
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: builder
|
27
|
-
requirement: &
|
27
|
+
requirement: &2153464920 !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: *2153464920
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: multi_json
|
38
|
-
requirement: &
|
38
|
+
requirement: &2153464460 !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: *2153464460
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: multi_xml
|
49
|
-
requirement: &
|
49
|
+
requirement: &2153464000 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,21 @@ dependencies:
|
|
54
54
|
version: 0.3.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2153464000
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: countries
|
60
|
+
requirement: &2153463620 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2153463620
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: rspec
|
60
|
-
requirement: &
|
71
|
+
requirement: &2153463080 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ~>
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '2.4'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *2153463080
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: vcr
|
71
|
-
requirement: &
|
82
|
+
requirement: &2153462580 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ~>
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '1.7'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *2153462580
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: webmock
|
82
|
-
requirement: &
|
93
|
+
requirement: &2153462120 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ~>
|
@@ -87,10 +98,10 @@ dependencies:
|
|
87
98
|
version: '1.6'
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *2153462120
|
91
102
|
- !ruby/object:Gem::Dependency
|
92
103
|
name: factory_girl
|
93
|
-
requirement: &
|
104
|
+
requirement: &2153461660 !ruby/object:Gem::Requirement
|
94
105
|
none: false
|
95
106
|
requirements:
|
96
107
|
- - ~>
|
@@ -98,10 +109,10 @@ dependencies:
|
|
98
109
|
version: '1.3'
|
99
110
|
type: :development
|
100
111
|
prerelease: false
|
101
|
-
version_requirements: *
|
112
|
+
version_requirements: *2153461660
|
102
113
|
- !ruby/object:Gem::Dependency
|
103
114
|
name: faker
|
104
|
-
requirement: &
|
115
|
+
requirement: &2153461200 !ruby/object:Gem::Requirement
|
105
116
|
none: false
|
106
117
|
requirements:
|
107
118
|
- - ~>
|
@@ -109,10 +120,10 @@ dependencies:
|
|
109
120
|
version: '0.9'
|
110
121
|
type: :development
|
111
122
|
prerelease: false
|
112
|
-
version_requirements: *
|
123
|
+
version_requirements: *2153461200
|
113
124
|
- !ruby/object:Gem::Dependency
|
114
125
|
name: rake
|
115
|
-
requirement: &
|
126
|
+
requirement: &2153460740 !ruby/object:Gem::Requirement
|
116
127
|
none: false
|
117
128
|
requirements:
|
118
129
|
- - ~>
|
@@ -120,10 +131,10 @@ dependencies:
|
|
120
131
|
version: '0.9'
|
121
132
|
type: :development
|
122
133
|
prerelease: false
|
123
|
-
version_requirements: *
|
134
|
+
version_requirements: *2153460740
|
124
135
|
- !ruby/object:Gem::Dependency
|
125
136
|
name: watchr
|
126
|
-
requirement: &
|
137
|
+
requirement: &2153460360 !ruby/object:Gem::Requirement
|
127
138
|
none: false
|
128
139
|
requirements:
|
129
140
|
- - ! '>='
|
@@ -131,10 +142,10 @@ dependencies:
|
|
131
142
|
version: '0'
|
132
143
|
type: :development
|
133
144
|
prerelease: false
|
134
|
-
version_requirements: *
|
145
|
+
version_requirements: *2153460360
|
135
146
|
- !ruby/object:Gem::Dependency
|
136
147
|
name: open4
|
137
|
-
requirement: &
|
148
|
+
requirement: &2153476260 !ruby/object:Gem::Requirement
|
138
149
|
none: false
|
139
150
|
requirements:
|
140
151
|
- - ! '>='
|
@@ -142,10 +153,10 @@ dependencies:
|
|
142
153
|
version: '0'
|
143
154
|
type: :development
|
144
155
|
prerelease: false
|
145
|
-
version_requirements: *
|
156
|
+
version_requirements: *2153476260
|
146
157
|
- !ruby/object:Gem::Dependency
|
147
158
|
name: appraisal
|
148
|
-
requirement: &
|
159
|
+
requirement: &2153475840 !ruby/object:Gem::Requirement
|
149
160
|
none: false
|
150
161
|
requirements:
|
151
162
|
- - ! '>='
|
@@ -153,7 +164,7 @@ dependencies:
|
|
153
164
|
version: '0'
|
154
165
|
type: :development
|
155
166
|
prerelease: false
|
156
|
-
version_requirements: *
|
167
|
+
version_requirements: *2153475840
|
157
168
|
description: Several card processors and gateways support offloading the storage of
|
158
169
|
credit card information onto their service. This offloads PCI compliance to the
|
159
170
|
gateway rather than keeping it with each retailer. This library abstracts the interface
|