activemerchant 1.31.0 → 1.32.0
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/CHANGELOG +29 -0
- data/CONTRIBUTORS +8 -0
- data/README.md +2 -0
- data/lib/active_merchant/billing/credit_card.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -1
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +1 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +1 -0
- data/lib/active_merchant/billing/gateways/cc5.rb +160 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +1 -1
- data/lib/active_merchant/billing/gateways/data_cash.rb +3 -3
- data/lib/active_merchant/billing/gateways/finansbank.rb +22 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +8 -2
- data/lib/active_merchant/billing/gateways/litle.rb +289 -101
- data/lib/active_merchant/billing/gateways/ogone.rb +1 -1
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +26 -16
- data/lib/active_merchant/billing/gateways/orbital.rb +6 -6
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +2 -1
- data/lib/active_merchant/billing/gateways/paymill.rb +13 -9
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +14 -9
- data/lib/active_merchant/billing/gateways/pin.rb +13 -5
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +15 -17
- data/lib/active_merchant/billing/gateways/stripe.rb +25 -12
- data/lib/active_merchant/billing/gateways/webpay.rb +8 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +44 -22
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +3 -2
- data/lib/active_merchant/billing/integrations/pxpay/helper.rb +1 -0
- data/lib/active_merchant/billing/integrations/robokassa/common.rb +1 -1
- data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +5 -1
- data/lib/active_merchant/billing/integrations/world_pay.rb +15 -8
- data/lib/active_merchant/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +82 -26
- metadata.gz.sig +0 -0
|
@@ -37,7 +37,7 @@ module ActiveMerchant #:nodoc:
|
|
|
37
37
|
self.test_url = 'https://www.testlitle.com/sandbox/communicator/online'
|
|
38
38
|
self.live_url = 'https://payments.litle.com/vap/communicator/online'
|
|
39
39
|
|
|
40
|
-
LITLE_SCHEMA_VERSION
|
|
40
|
+
LITLE_SCHEMA_VERSION = '8.13'
|
|
41
41
|
|
|
42
42
|
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
|
43
43
|
self.supported_countries = ['US']
|
|
@@ -46,10 +46,10 @@ module ActiveMerchant #:nodoc:
|
|
|
46
46
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
|
47
47
|
|
|
48
48
|
# The homepage URL of the gateway
|
|
49
|
-
self.homepage_url
|
|
49
|
+
self.homepage_url = 'http://www.litle.com/'
|
|
50
50
|
|
|
51
51
|
# The name of the gateway
|
|
52
|
-
self.display_name
|
|
52
|
+
self.display_name = 'Litle & Co.'
|
|
53
53
|
|
|
54
54
|
self.default_currency = 'USD'
|
|
55
55
|
|
|
@@ -91,8 +91,8 @@ module ActiveMerchant #:nodoc:
|
|
|
91
91
|
build_response(:void, @litle.void(to_pass))
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
def credit(money,
|
|
95
|
-
to_pass =
|
|
94
|
+
def credit(money, identification_or_token, options = {})
|
|
95
|
+
to_pass = build_credit_request(money, identification_or_token, options)
|
|
96
96
|
build_response(:credit, @litle.credit(to_pass))
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -104,30 +104,30 @@ module ActiveMerchant #:nodoc:
|
|
|
104
104
|
private
|
|
105
105
|
|
|
106
106
|
CARD_TYPE = {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
'visa' => 'VI',
|
|
108
|
+
'master' => 'MC',
|
|
109
|
+
'american_express' => 'AX',
|
|
110
|
+
'discover' => 'DI',
|
|
111
|
+
'jcb' => 'DI',
|
|
112
|
+
'diners_club' => 'DI'
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
AVS_RESPONSE_CODE = {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
116
|
+
'00' => 'Y',
|
|
117
|
+
'01' => 'X',
|
|
118
|
+
'02' => 'D',
|
|
119
|
+
'10' => 'Z',
|
|
120
|
+
'11' => 'W',
|
|
121
|
+
'12' => 'A',
|
|
122
|
+
'13' => 'A',
|
|
123
|
+
'14' => 'P',
|
|
124
|
+
'20' => 'N',
|
|
125
|
+
'30' => 'S',
|
|
126
|
+
'31' => 'R',
|
|
127
|
+
'32' => 'U',
|
|
128
|
+
'33' => 'R',
|
|
129
|
+
'34' => 'I',
|
|
130
|
+
'40' => 'E'
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
def url
|
|
@@ -140,22 +140,22 @@ module ActiveMerchant #:nodoc:
|
|
|
140
140
|
response = Hash.from_xml(litle_response.raw_xml.to_s)['litleOnlineResponse']
|
|
141
141
|
|
|
142
142
|
if response['response'] == "0"
|
|
143
|
-
detail
|
|
144
|
-
fraud
|
|
143
|
+
detail = response["#{kind}Response"]
|
|
144
|
+
fraud = fraud_result(detail)
|
|
145
145
|
authorization = case kind
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
146
|
+
when :registerToken
|
|
147
|
+
response['registerTokenResponse']['litleToken']
|
|
148
|
+
else
|
|
149
|
+
detail['litleTxnId']
|
|
150
|
+
end
|
|
151
151
|
Response.new(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
valid_responses.include?(detail['response']),
|
|
153
|
+
detail['message'],
|
|
154
|
+
{ :litleOnlineResponse => response },
|
|
155
|
+
:authorization => authorization,
|
|
156
|
+
:avs_result => { :code => fraud['avs'] },
|
|
157
|
+
:cvv_result => fraud['cvv'],
|
|
158
|
+
:test => test?
|
|
159
159
|
)
|
|
160
160
|
else
|
|
161
161
|
Response.new(false, response['message'], :litleOnlineResponse => response, :test => test?)
|
|
@@ -163,39 +163,83 @@ module ActiveMerchant #:nodoc:
|
|
|
163
163
|
end
|
|
164
164
|
|
|
165
165
|
def build_authorize_request(money, creditcard_or_token, options)
|
|
166
|
+
payment_method = build_payment_method(creditcard_or_token, options)
|
|
167
|
+
|
|
166
168
|
hash = create_hash(money, options)
|
|
167
169
|
|
|
168
|
-
|
|
170
|
+
add_creditcard_or_cardtoken_hash(hash, payment_method)
|
|
169
171
|
|
|
170
172
|
hash
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
def build_purchase_request(money, creditcard_or_token, options)
|
|
176
|
+
payment_method = build_payment_method(creditcard_or_token, options)
|
|
177
|
+
|
|
178
|
+
hash = create_hash(money, options)
|
|
179
|
+
|
|
180
|
+
add_creditcard_or_cardtoken_hash(hash, payment_method)
|
|
181
|
+
|
|
182
|
+
hash
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def build_credit_request(money, identification_or_token, options)
|
|
186
|
+
payment_method = build_payment_method(identification_or_token, options)
|
|
187
|
+
|
|
174
188
|
hash = create_hash(money, options)
|
|
175
189
|
|
|
176
|
-
|
|
190
|
+
add_identification_or_cardtoken_hash(hash, payment_method)
|
|
191
|
+
|
|
192
|
+
unless payment_method.is_a?(LitleCardToken)
|
|
193
|
+
hash['orderSource'] = nil
|
|
194
|
+
hash['orderId'] = nil
|
|
195
|
+
end
|
|
177
196
|
|
|
178
197
|
hash
|
|
179
198
|
end
|
|
180
199
|
|
|
181
|
-
def
|
|
182
|
-
|
|
183
|
-
|
|
200
|
+
def build_payment_method(payment_method, options)
|
|
201
|
+
result = payment_method
|
|
202
|
+
|
|
203
|
+
# Build instance of the LitleCardToken class for internal use if this is a token request.
|
|
204
|
+
if payment_method.is_a?(String) && options.has_key?(:token)
|
|
205
|
+
result = LitleCardToken.new(:token => payment_method)
|
|
206
|
+
result.month = options[:token][:month]
|
|
207
|
+
result.year = options[:token][:year]
|
|
208
|
+
result.verification_value = options[:token][:verification_value]
|
|
209
|
+
result.brand = options[:token][:brand]
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
result
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def add_creditcard_or_cardtoken_hash(hash, creditcard_or_cardtoken)
|
|
216
|
+
if creditcard_or_cardtoken.is_a?(LitleCardToken)
|
|
217
|
+
add_cardtoken_hash(hash, creditcard_or_cardtoken)
|
|
184
218
|
else
|
|
185
|
-
|
|
219
|
+
add_creditcard_hash(hash, creditcard_or_cardtoken)
|
|
186
220
|
end
|
|
187
221
|
end
|
|
188
222
|
|
|
189
|
-
def
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
def add_identification_or_cardtoken_hash(hash, identification_or_cardtoken)
|
|
224
|
+
if identification_or_cardtoken.is_a?(LitleCardToken)
|
|
225
|
+
add_cardtoken_hash(hash, identification_or_cardtoken)
|
|
226
|
+
else
|
|
227
|
+
hash['litleTxnId'] = identification_or_cardtoken
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def add_cardtoken_hash(hash, cardtoken)
|
|
232
|
+
token_info = {}
|
|
233
|
+
token_info['litleToken'] = cardtoken.token
|
|
234
|
+
token_info['expDate'] = cardtoken.exp_date if cardtoken.exp_date?
|
|
235
|
+
token_info['cardValidationNum'] = cardtoken.verification_value unless cardtoken.verification_value.blank?
|
|
236
|
+
token_info['type'] = cardtoken.type unless cardtoken.type.blank?
|
|
193
237
|
|
|
194
238
|
hash['token'] = token_info
|
|
195
239
|
hash
|
|
196
240
|
end
|
|
197
241
|
|
|
198
|
-
def
|
|
242
|
+
def add_creditcard_hash(hash, creditcard)
|
|
199
243
|
cc_type = CARD_TYPE[creditcard.brand]
|
|
200
244
|
exp_date_yr = creditcard.year.to_s[2..3]
|
|
201
245
|
exp_date_mo = '%02d' % creditcard.month.to_i
|
|
@@ -213,27 +257,19 @@ module ActiveMerchant #:nodoc:
|
|
|
213
257
|
end
|
|
214
258
|
|
|
215
259
|
def create_capture_hash(money, authorization, options)
|
|
216
|
-
hash
|
|
260
|
+
hash = create_hash(money, options)
|
|
217
261
|
hash['litleTxnId'] = authorization
|
|
218
262
|
hash
|
|
219
263
|
end
|
|
220
264
|
|
|
221
|
-
def create_credit_hash(money, identification, options)
|
|
222
|
-
hash = create_hash(money, options)
|
|
223
|
-
hash['litleTxnId'] = identification
|
|
224
|
-
hash['orderSource'] = nil
|
|
225
|
-
hash['orderId'] = nil
|
|
226
|
-
hash
|
|
227
|
-
end
|
|
228
|
-
|
|
229
265
|
def create_token_hash(creditcard, options)
|
|
230
|
-
hash
|
|
266
|
+
hash = create_hash(0, options)
|
|
231
267
|
hash['accountNumber'] = creditcard.number
|
|
232
268
|
hash
|
|
233
269
|
end
|
|
234
270
|
|
|
235
271
|
def create_void_hash(identification, options)
|
|
236
|
-
hash
|
|
272
|
+
hash = create_hash(nil, options)
|
|
237
273
|
hash['litleTxnId'] = identification
|
|
238
274
|
hash
|
|
239
275
|
end
|
|
@@ -255,54 +291,54 @@ module ActiveMerchant #:nodoc:
|
|
|
255
291
|
|
|
256
292
|
if options[:billing_address]
|
|
257
293
|
bill_to_address = {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
294
|
+
'name' => options[:billing_address][:name],
|
|
295
|
+
'companyName' => options[:billing_address][:company],
|
|
296
|
+
'addressLine1' => options[:billing_address][:address1],
|
|
297
|
+
'addressLine2' => options[:billing_address][:address2],
|
|
298
|
+
'city' => options[:billing_address][:city],
|
|
299
|
+
'state' => options[:billing_address][:state],
|
|
300
|
+
'zip' => options[:billing_address][:zip],
|
|
301
|
+
'country' => options[:billing_address][:country],
|
|
302
|
+
'email' => options[:email],
|
|
303
|
+
'phone' => options[:billing_address][:phone]
|
|
268
304
|
}
|
|
269
305
|
end
|
|
270
306
|
if options[:shipping_address]
|
|
271
307
|
ship_to_address = {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
308
|
+
'name' => options[:shipping_address][:name],
|
|
309
|
+
'companyName' => options[:shipping_address][:company],
|
|
310
|
+
'addressLine1' => options[:shipping_address][:address1],
|
|
311
|
+
'addressLine2' => options[:shipping_address][:address2],
|
|
312
|
+
'city' => options[:shipping_address][:city],
|
|
313
|
+
'state' => options[:shipping_address][:state],
|
|
314
|
+
'zip' => options[:shipping_address][:zip],
|
|
315
|
+
'country' => options[:shipping_address][:country],
|
|
316
|
+
'email' => options[:email],
|
|
317
|
+
'phone' => options[:shipping_address][:phone]
|
|
282
318
|
}
|
|
283
319
|
end
|
|
284
320
|
|
|
285
321
|
hash = {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
322
|
+
'billToAddress' => bill_to_address,
|
|
323
|
+
'shipToAddress' => ship_to_address,
|
|
324
|
+
'orderId' => (options[:order_id] || @options[:order_id]),
|
|
325
|
+
'customerId' => options[:customer],
|
|
326
|
+
'reportGroup' => (options[:merchant] || @options[:merchant]),
|
|
327
|
+
'merchantId' => (options[:merchant_id] || @options[:merchant_id]),
|
|
328
|
+
'orderSource' => (options[:order_source] || 'ecommerce'),
|
|
329
|
+
'enhancedData' => enhanced_data,
|
|
330
|
+
'fraudCheckType' => fraud_check_type,
|
|
331
|
+
'user' => (options[:user] || @options[:user]),
|
|
332
|
+
'password' => (options[:password] || @options[:password]),
|
|
333
|
+
'version' => (options[:version] || @options[:version]),
|
|
334
|
+
'url' => (options[:url] || url),
|
|
335
|
+
'proxy_addr' => (options[:proxy_addr] || @options[:proxy_addr]),
|
|
336
|
+
'proxy_port' => (options[:proxy_port] || @options[:proxy_port]),
|
|
337
|
+
'id' => (options[:id] || options[:order_id] || @options[:order_id])
|
|
302
338
|
}
|
|
303
339
|
|
|
304
|
-
if(
|
|
305
|
-
hash.merge!({'amount' => money})
|
|
340
|
+
if (!money.nil? && money.to_s.length > 0)
|
|
341
|
+
hash.merge!({ 'amount' => money })
|
|
306
342
|
end
|
|
307
343
|
hash
|
|
308
344
|
end
|
|
@@ -315,7 +351,159 @@ module ActiveMerchant #:nodoc:
|
|
|
315
351
|
|
|
316
352
|
avs_to_pass = AVS_RESPONSE_CODE[result['avsResult']] unless result['avsResult'].blank?
|
|
317
353
|
end
|
|
318
|
-
{'cvv'=>cvv_to_pass, 'avs'=>avs_to_pass}
|
|
354
|
+
{ 'cvv' => cvv_to_pass, 'avs' => avs_to_pass }
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# A +LitleCardToken+ object represents a tokenized credit card, and is capable of validating the various
|
|
358
|
+
# data associated with these.
|
|
359
|
+
#
|
|
360
|
+
# == Example Usage
|
|
361
|
+
# token = LitleCardToken.new(
|
|
362
|
+
# :token => '1234567890123456',
|
|
363
|
+
# :month => '9',
|
|
364
|
+
# :year => '2010',
|
|
365
|
+
# :brand => 'visa',
|
|
366
|
+
# :verification_value => '123'
|
|
367
|
+
# )
|
|
368
|
+
#
|
|
369
|
+
# token.valid? # => true
|
|
370
|
+
# cc.exp_date # => 0910
|
|
371
|
+
#
|
|
372
|
+
class LitleCardToken
|
|
373
|
+
include Validateable
|
|
374
|
+
|
|
375
|
+
# Returns or sets the token. (required)
|
|
376
|
+
#
|
|
377
|
+
# @return [String]
|
|
378
|
+
attr_accessor :token
|
|
379
|
+
|
|
380
|
+
# Returns or sets the expiry month for the card associated with token. (optional)
|
|
381
|
+
#
|
|
382
|
+
# @return [Integer]
|
|
383
|
+
attr_accessor :month
|
|
384
|
+
|
|
385
|
+
# Returns or sets the expiry year for the card associated with token. (optional)
|
|
386
|
+
#
|
|
387
|
+
# @return [Integer]
|
|
388
|
+
attr_accessor :year
|
|
389
|
+
|
|
390
|
+
# Returns or sets the card verification value. (optional)
|
|
391
|
+
#
|
|
392
|
+
# @return [String] the verification value
|
|
393
|
+
attr_accessor :verification_value
|
|
394
|
+
|
|
395
|
+
# Returns or sets the credit card brand. (optional)
|
|
396
|
+
#
|
|
397
|
+
# Valid card types are
|
|
398
|
+
#
|
|
399
|
+
# * +'visa'+
|
|
400
|
+
# * +'master'+
|
|
401
|
+
# * +'discover'+
|
|
402
|
+
# * +'american_express'+
|
|
403
|
+
# * +'diners_club'+
|
|
404
|
+
# * +'jcb'+
|
|
405
|
+
# * +'switch'+
|
|
406
|
+
# * +'solo'+
|
|
407
|
+
# * +'dankort'+
|
|
408
|
+
# * +'maestro'+
|
|
409
|
+
# * +'forbrugsforeningen'+
|
|
410
|
+
# * +'laser'+
|
|
411
|
+
#
|
|
412
|
+
# @return (String) the credit card brand
|
|
413
|
+
attr_accessor :brand
|
|
414
|
+
|
|
415
|
+
# Returns the Litle credit card type identifier.
|
|
416
|
+
#
|
|
417
|
+
# @return (String) the credit card type identifier
|
|
418
|
+
def type
|
|
419
|
+
CARD_TYPE[brand] unless brand.blank?
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Returns true if the expiration date is set.
|
|
423
|
+
#
|
|
424
|
+
# @return (Boolean)
|
|
425
|
+
def exp_date?
|
|
426
|
+
!month.to_i.zero? && !year.to_i.zero?
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Returns the card token expiration date in MMYY format.
|
|
430
|
+
#
|
|
431
|
+
# @return (String) the expiration date in MMYY format
|
|
432
|
+
def exp_date
|
|
433
|
+
result = ''
|
|
434
|
+
if exp_date?
|
|
435
|
+
exp_date_yr = year.to_s[2..3]
|
|
436
|
+
exp_date_mo = '%02d' % month.to_i
|
|
437
|
+
|
|
438
|
+
result = exp_date_mo + exp_date_yr
|
|
439
|
+
end
|
|
440
|
+
result
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Validates the card token details.
|
|
444
|
+
#
|
|
445
|
+
# Any validation errors are added to the {#errors} attribute.
|
|
446
|
+
def validate
|
|
447
|
+
validate_card_token
|
|
448
|
+
validate_expiration_date
|
|
449
|
+
validate_card_brand
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def check?
|
|
453
|
+
false
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
private
|
|
457
|
+
|
|
458
|
+
CARD_TYPE = {
|
|
459
|
+
'visa' => 'VI',
|
|
460
|
+
'master' => 'MC',
|
|
461
|
+
'american_express' => 'AX',
|
|
462
|
+
'discover' => 'DI',
|
|
463
|
+
'jcb' => 'DI',
|
|
464
|
+
'diners_club' => 'DI'
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
def before_validate #:nodoc:
|
|
468
|
+
self.month = month.to_i
|
|
469
|
+
self.year = year.to_i
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
# Litle XML Reference Guide 1.8.2
|
|
473
|
+
#
|
|
474
|
+
# The length of the original card number is reflected in the token, so a
|
|
475
|
+
# submitted 16-digit number results in a 16-digit token. Also, all tokens
|
|
476
|
+
# use only numeric characters, so you do not have to change your
|
|
477
|
+
# systems to accept alpha-numeric characters.
|
|
478
|
+
#
|
|
479
|
+
# The credit card token numbers themselves have two parts.
|
|
480
|
+
# The last four digits match the last four digits of the card number.
|
|
481
|
+
# The remaining digits (length can vary based upon original card number
|
|
482
|
+
# length) are a randomly generated.
|
|
483
|
+
def validate_card_token #:nodoc:
|
|
484
|
+
if token.to_s.length < 12 || token.to_s.match(/\A\d+\Z/).nil?
|
|
485
|
+
errors.add :token, "is not a valid card token"
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
def validate_expiration_date #:nodoc:
|
|
490
|
+
if !month.to_i.zero? || !year.to_i.zero?
|
|
491
|
+
errors.add :month, "is not a valid month" unless valid_month?(month)
|
|
492
|
+
errors.add :year, "is not a valid year" unless valid_expiry_year?(year)
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def validate_card_brand #:nodoc:
|
|
497
|
+
errors.add :brand, "is invalid" unless brand.blank? || CreditCard.card_companies.keys.include?(brand)
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def valid_month?(month)
|
|
501
|
+
(1..12).include?(month.to_i)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def valid_expiry_year?(year)
|
|
505
|
+
year.to_s =~ /\A\d{4}\Z/ && year.to_i > 1987
|
|
506
|
+
end
|
|
319
507
|
end
|
|
320
508
|
end
|
|
321
509
|
end
|
|
@@ -200,7 +200,7 @@ module ActiveMerchant #:nodoc:
|
|
|
200
200
|
|
|
201
201
|
# Store a credit card by creating an Ogone Alias
|
|
202
202
|
def store(payment_source, options = {})
|
|
203
|
-
options.merge!(:alias_operation => '
|
|
203
|
+
options.merge!(:alias_operation => 'BYPSP') unless(options.has_key?(:billing_id) || options.has_key?(:store))
|
|
204
204
|
response = authorize(1, payment_source, options)
|
|
205
205
|
void(response.authorization) if response.success?
|
|
206
206
|
response
|
|
@@ -160,6 +160,7 @@ module ActiveMerchant #:nodoc:
|
|
|
160
160
|
xml.amount(money/100.0)
|
|
161
161
|
build_card(xml, opts)
|
|
162
162
|
build_billing_details(xml, opts)
|
|
163
|
+
build_shipping_details(xml, opts)
|
|
163
164
|
end
|
|
164
165
|
end
|
|
165
166
|
|
|
@@ -250,24 +251,33 @@ module ActiveMerchant #:nodoc:
|
|
|
250
251
|
|
|
251
252
|
def build_billing_details(xml, opts)
|
|
252
253
|
xml.tag! 'billingDetails' do
|
|
253
|
-
addr = opts[:billing_address]
|
|
254
254
|
xml.tag! 'cardPayMethod', 'WEB'
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
xml
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
xml.tag! '
|
|
268
|
-
xml.tag! '
|
|
269
|
-
|
|
255
|
+
build_address(xml, opts[:billing_address], opts[:email])
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def build_shipping_details(xml, opts)
|
|
260
|
+
xml.tag! 'shippingDetails' do
|
|
261
|
+
build_address(xml, opts[:shipping_address], opts[:email])
|
|
262
|
+
end if opts[:shipping_address].present?
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def build_address(xml, addr, email=nil)
|
|
266
|
+
if addr[:name]
|
|
267
|
+
xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
|
|
268
|
+
xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
|
|
269
|
+
end
|
|
270
|
+
xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1].present?
|
|
271
|
+
xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2].present?
|
|
272
|
+
xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city].present?
|
|
273
|
+
if addr[:state].present?
|
|
274
|
+
state_tag = %w(US CA).include?(addr[:country]) ? 'state' : 'region'
|
|
275
|
+
xml.tag! state_tag, CGI.escape(addr[:state])
|
|
270
276
|
end
|
|
277
|
+
xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
|
|
278
|
+
xml.tag! 'zip' , CGI.escape(addr[:zip] ) if addr[:zip].present?
|
|
279
|
+
xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
|
|
280
|
+
xml.tag! 'email', CGI.escape(email) if email
|
|
271
281
|
end
|
|
272
282
|
|
|
273
283
|
def card_type(key)
|
|
@@ -219,14 +219,14 @@ module ActiveMerchant #:nodoc:
|
|
|
219
219
|
avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s)
|
|
220
220
|
|
|
221
221
|
if avs_supported
|
|
222
|
-
xml.tag! :AVSzip, address[:zip]
|
|
223
|
-
xml.tag! :AVSaddress1, address[:address1]
|
|
224
|
-
xml.tag! :AVSaddress2, address[:address2]
|
|
225
|
-
xml.tag! :AVScity, address[:city]
|
|
222
|
+
xml.tag! :AVSzip, address[:zip].to_s[0..9]
|
|
223
|
+
xml.tag! :AVSaddress1, address[:address1][0..29]
|
|
224
|
+
xml.tag! :AVSaddress2, address[:address2][0..29]
|
|
225
|
+
xml.tag! :AVScity, address[:city][0..19]
|
|
226
226
|
xml.tag! :AVSstate, address[:state]
|
|
227
|
-
xml.tag! :AVSphoneNum, address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil
|
|
227
|
+
xml.tag! :AVSphoneNum, address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil
|
|
228
228
|
end
|
|
229
|
-
xml.tag! :AVSname, creditcard.name
|
|
229
|
+
xml.tag! :AVSname, creditcard.name[0..29]
|
|
230
230
|
xml.tag! :AVScountryCode, avs_supported ? address[:country] : ''
|
|
231
231
|
end
|
|
232
232
|
end
|
|
@@ -121,7 +121,8 @@ module ActiveMerchant #:nodoc:
|
|
|
121
121
|
def add_address(xml, tag, address, options)
|
|
122
122
|
return if address.nil?
|
|
123
123
|
xml.tag! tag do
|
|
124
|
-
xml.tag! '
|
|
124
|
+
xml.tag! 'FirstName', address[:first_name] unless address[:first_name].blank?
|
|
125
|
+
xml.tag! 'LastName', address[:last_name] unless address[:last_name].blank?
|
|
125
126
|
xml.tag! 'EMail', options[:email] unless options[:email].blank?
|
|
126
127
|
xml.tag! 'Phone', address[:phone] unless address[:phone].blank?
|
|
127
128
|
xml.tag! 'CustCode', options[:customer] if !options[:customer].blank? && tag == 'BillTo'
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
|
2
2
|
module Billing #:nodoc:
|
|
3
3
|
class PaymillGateway < Gateway
|
|
4
|
-
self.supported_countries = %w(AT BE
|
|
5
|
-
IS IT LI LU LV NL NO PL PT
|
|
4
|
+
self.supported_countries = %w(AD AT BE CY CZ DE DK EE ES FI FO FR GB GR
|
|
5
|
+
HU IE IL IS IT LI LT LU LV MT NL NO PL PT
|
|
6
|
+
SE SI SK TR VA)
|
|
6
7
|
|
|
7
8
|
self.supported_cardtypes = [:visa, :master]
|
|
8
9
|
self.homepage_url = 'https://paymill.com'
|
|
@@ -123,20 +124,23 @@ module ActiveMerchant #:nodoc:
|
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
def response_for_save_from(raw_response)
|
|
126
|
-
parsed = JSON.parse(raw_response.sub(/jsonPFunction\(/, '').sub(/\)\z/, ''))
|
|
127
|
-
succeeded = parsed['transaction']['processing']['result'] == 'ACK'
|
|
128
|
-
|
|
129
127
|
options = { :test => test? }
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
|
|
129
|
+
parsed = JSON.parse(raw_response.sub(/jsonPFunction\(/, '').sub(/\)\z/, ''))
|
|
130
|
+
if parsed['error']
|
|
131
|
+
succeeded = false
|
|
132
|
+
message = parsed['error']['message']
|
|
133
|
+
else
|
|
134
|
+
succeeded = parsed['transaction']['processing']['result'] == 'ACK'
|
|
135
|
+
message = parsed['transaction']['processing']['return']['message']
|
|
136
|
+
options[:authorization] = parsed['transaction']['identification']['uniqueId'] if succeeded
|
|
132
137
|
end
|
|
133
138
|
|
|
134
|
-
message = parsed['transaction']['processing']['return']['message']
|
|
135
139
|
Response.new(succeeded, message, parsed, options)
|
|
136
140
|
end
|
|
137
141
|
|
|
138
142
|
def save_card_url
|
|
139
|
-
(test? ? 'https://test-token.paymill.
|
|
143
|
+
(test? ? 'https://test-token.paymill.com' : 'https://token-v2.paymill.com')
|
|
140
144
|
end
|
|
141
145
|
|
|
142
146
|
def post_data(params)
|