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.
Files changed (33) hide show
  1. data/CHANGELOG +29 -0
  2. data/CONTRIBUTORS +8 -0
  3. data/README.md +2 -0
  4. data/lib/active_merchant/billing/credit_card.rb +1 -1
  5. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -1
  6. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +1 -0
  7. data/lib/active_merchant/billing/gateways/braintree_blue.rb +1 -0
  8. data/lib/active_merchant/billing/gateways/cc5.rb +160 -0
  9. data/lib/active_merchant/billing/gateways/cyber_source.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/data_cash.rb +3 -3
  11. data/lib/active_merchant/billing/gateways/finansbank.rb +22 -0
  12. data/lib/active_merchant/billing/gateways/iridium.rb +8 -2
  13. data/lib/active_merchant/billing/gateways/litle.rb +289 -101
  14. data/lib/active_merchant/billing/gateways/ogone.rb +1 -1
  15. data/lib/active_merchant/billing/gateways/optimal_payment.rb +26 -16
  16. data/lib/active_merchant/billing/gateways/orbital.rb +6 -6
  17. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +2 -1
  18. data/lib/active_merchant/billing/gateways/paymill.rb +13 -9
  19. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +14 -9
  20. data/lib/active_merchant/billing/gateways/pin.rb +13 -5
  21. data/lib/active_merchant/billing/gateways/spreedly_core.rb +15 -17
  22. data/lib/active_merchant/billing/gateways/stripe.rb +25 -12
  23. data/lib/active_merchant/billing/gateways/webpay.rb +8 -0
  24. data/lib/active_merchant/billing/gateways/worldpay.rb +44 -22
  25. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +3 -2
  26. data/lib/active_merchant/billing/integrations/pxpay/helper.rb +1 -0
  27. data/lib/active_merchant/billing/integrations/robokassa/common.rb +1 -1
  28. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +5 -1
  29. data/lib/active_merchant/billing/integrations/world_pay.rb +15 -8
  30. data/lib/active_merchant/version.rb +1 -1
  31. data.tar.gz.sig +0 -0
  32. metadata +82 -26
  33. 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 = '8.10'
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 = 'http://www.litle.com/'
49
+ self.homepage_url = 'http://www.litle.com/'
50
50
 
51
51
  # The name of the gateway
52
- self.display_name = 'Litle & Co.'
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, identification, options = {})
95
- to_pass = create_credit_hash(money, identification, options)
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
- 'visa' => 'VI',
108
- 'master' => 'MC',
109
- 'american_express' => 'AX',
110
- 'discover' => 'DI',
111
- 'jcb' => 'DI',
112
- 'diners_club' => 'DI'
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
- '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'
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 = response["#{kind}Response"]
144
- fraud = fraud_result(detail)
143
+ detail = response["#{kind}Response"]
144
+ fraud = fraud_result(detail)
145
145
  authorization = case kind
146
- when :registerToken
147
- response['registerTokenResponse']['litleToken']
148
- else
149
- detail['litleTxnId']
150
- end
146
+ when :registerToken
147
+ response['registerTokenResponse']['litleToken']
148
+ else
149
+ detail['litleTxnId']
150
+ end
151
151
  Response.new(
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?
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
- add_credit_card_or_token_hash(hash, creditcard_or_token)
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
- add_credit_card_or_token_hash(hash, creditcard_or_token)
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 add_credit_card_or_token_hash(hash, creditcard_or_token)
182
- if creditcard_or_token.is_a?(String)
183
- add_token_hash(hash, creditcard_or_token)
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
- add_credit_card_hash(hash, creditcard_or_token)
219
+ add_creditcard_hash(hash, creditcard_or_cardtoken)
186
220
  end
187
221
  end
188
222
 
189
- def add_token_hash(hash, creditcard_or_token)
190
- token_info = {
191
- 'litleToken' => creditcard_or_token
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 add_credit_card_hash(hash, creditcard)
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 = create_hash(money, options)
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 = create_hash(0, options)
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 = create_hash(nil, options)
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
- 'name' => options[:billing_address][:name],
259
- 'companyName' => options[:billing_address][:company],
260
- 'addressLine1' => options[:billing_address][:address1],
261
- 'addressLine2' => options[:billing_address][:address2],
262
- 'city' => options[:billing_address][:city],
263
- 'state' => options[:billing_address][:state],
264
- 'zip' => options[:billing_address][:zip],
265
- 'country' => options[:billing_address][:country],
266
- 'email' => options[:email],
267
- 'phone' => options[:billing_address][:phone]
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
- 'name' => options[:shipping_address][:name],
273
- 'companyName' => options[:shipping_address][:company],
274
- 'addressLine1' => options[:shipping_address][:address1],
275
- 'addressLine2' => options[:shipping_address][:address2],
276
- 'city' => options[:shipping_address][:city],
277
- 'state' => options[:shipping_address][:state],
278
- 'zip' => options[:shipping_address][:zip],
279
- 'country' => options[:shipping_address][:country],
280
- 'email' => options[:email],
281
- 'phone' => options[:shipping_address][:phone]
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
- 'billToAddress' => bill_to_address,
287
- 'shipToAddress' => ship_to_address,
288
- 'orderId' => (options[:order_id] || @options[:order_id]),
289
- 'customerId' => options[:customer],
290
- 'reportGroup' => (options[:merchant] || @options[:merchant]),
291
- 'merchantId' => (options[:merchant_id] || @options[:merchant_id]),
292
- 'orderSource' => (options[:order_source] || 'ecommerce'),
293
- 'enhancedData' => enhanced_data,
294
- 'fraudCheckType' => fraud_check_type,
295
- 'user' => (options[:user] || @options[:user]),
296
- 'password' => (options[:password] || @options[:password]),
297
- 'version' => (options[:version] || @options[:version]),
298
- 'url' => (options[:url] || url),
299
- 'proxy_addr' => (options[:proxy_addr] || @options[:proxy_addr]),
300
- 'proxy_port' => (options[:proxy_port] || @options[:proxy_port]),
301
- 'id' => (options[:id] || options[:order_id] || @options[:order_id])
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( !money.nil? && money.to_s.length > 0 )
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 => 'BYOGONE') unless options.has_key?(:billing_id) || options.has_key?(:store)
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
- if addr[:name]
256
- xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
257
- xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
258
- end
259
- xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1].present?
260
- xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2].present?
261
- xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city].present?
262
- if addr[:state].present?
263
- state_tag = %w(US CA).include?(addr[:country]) ? 'state' : 'region'
264
- xml.tag! state_tag, CGI.escape(addr[:state])
265
- end
266
- xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
267
- xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
268
- xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
269
- xml.tag! 'email', CGI.escape(opts[:email]) if opts[:email]
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! 'Name', address[:name] unless address[:name].blank?
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 CH CZ DE DK EE ES FI FR GB HU IE
5
- IS IT LI LU LV NL NO PL PT SE SI TR)
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
- if succeeded
131
- options[:authorization] = parsed['transaction']['identification']['uniqueId']
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.de' : 'https://token-v2.paymill.de')
143
+ (test? ? 'https://test-token.paymill.com' : 'https://token-v2.paymill.com')
140
144
  end
141
145
 
142
146
  def post_data(params)