activemerchant 1.50.0 → 1.51.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +39 -0
  3. data/README.md +6 -5
  4. data/lib/active_merchant/billing/credit_card.rb +22 -6
  5. data/lib/active_merchant/billing/gateway.rb +15 -1
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +413 -127
  7. data/lib/active_merchant/billing/gateways/banwire.rb +2 -2
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +4 -0
  9. data/lib/active_merchant/billing/gateways/card_stream.rb +18 -0
  10. data/lib/active_merchant/billing/gateways/cenpos.rb +6 -2
  11. data/lib/active_merchant/billing/gateways/checkout.rb +4 -6
  12. data/lib/active_merchant/billing/gateways/checkout_v2.rb +200 -0
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +19 -1
  14. data/lib/active_merchant/billing/gateways/dibs.rb +1 -1
  15. data/lib/active_merchant/billing/gateways/epay.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/eway_rapid.rb +5 -5
  17. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +4 -1
  18. data/lib/active_merchant/billing/gateways/garanti.rb +5 -1
  19. data/lib/active_merchant/billing/gateways/iats_payments.rb +29 -3
  20. data/lib/active_merchant/billing/gateways/litle.rb +12 -0
  21. data/lib/active_merchant/billing/gateways/paystation.rb +19 -23
  22. data/lib/active_merchant/billing/gateways/payu_in.rb +4 -0
  23. data/lib/active_merchant/billing/gateways/redsys.rb +4 -3
  24. data/lib/active_merchant/billing/gateways/s5.rb +3 -3
  25. data/lib/active_merchant/billing/gateways/sage.rb +8 -10
  26. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +7 -5
  27. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +3 -2
  28. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +0 -5
  29. data/lib/active_merchant/billing/gateways/stripe.rb +33 -4
  30. data/lib/active_merchant/billing/gateways/wepay.rb +13 -6
  31. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +1 -2
  32. data/lib/active_merchant/version.rb +1 -1
  33. metadata +3 -2
@@ -109,6 +109,7 @@ module ActiveMerchant #:nodoc:
109
109
  doc.registerTokenRequest(transaction_attributes(options)) do
110
110
  doc.orderId(truncate(options[:order_id], 24))
111
111
  doc.accountNumber(creditcard.number)
112
+ doc.cardValidationNum(creditcard.verification_value) if creditcard.verification_value
112
113
  end
113
114
  end
114
115
 
@@ -163,6 +164,7 @@ module ActiveMerchant #:nodoc:
163
164
  add_payment_method(doc, payment_method)
164
165
  add_pos(doc, payment_method)
165
166
  add_descriptor(doc, options)
167
+ add_debt_repayment(doc, options)
166
168
  end
167
169
 
168
170
  def add_descriptor(doc, options)
@@ -174,6 +176,10 @@ module ActiveMerchant #:nodoc:
174
176
  end
175
177
  end
176
178
 
179
+ def add_debt_repayment(doc, options)
180
+ doc.debtRepayment(true) if options[:debt_repayment] == true
181
+ end
182
+
177
183
  def add_payment_method(doc, payment_method)
178
184
  if payment_method.is_a?(String)
179
185
  doc.token do
@@ -264,6 +270,12 @@ module ActiveMerchant #:nodoc:
264
270
  end
265
271
  end
266
272
 
273
+ if parsed.empty?
274
+ %w(response message).each do |attribute|
275
+ parsed[attribute.to_sym] = doc.xpath("//litleOnlineResponse").attribute(attribute).value
276
+ end
277
+ end
278
+
267
279
  parsed
268
280
  end
269
281
 
@@ -32,9 +32,7 @@ module ActiveMerchant #:nodoc:
32
32
 
33
33
  add_invoice(post, options)
34
34
  add_amount(post, money, options)
35
-
36
35
  add_credit_card(post, credit_card)
37
-
38
36
  add_authorize_flag(post, options)
39
37
 
40
38
  commit(post)
@@ -45,7 +43,6 @@ module ActiveMerchant #:nodoc:
45
43
 
46
44
  add_invoice(post, options)
47
45
  add_amount(post, money, options)
48
-
49
46
  add_authorization_token(post, authorization_token, options[:credit_card_verification])
50
47
 
51
48
  commit(post)
@@ -78,6 +75,16 @@ module ActiveMerchant #:nodoc:
78
75
  commit(post)
79
76
  end
80
77
 
78
+
79
+ def refund(money, authorization, options={})
80
+ post = new_request
81
+ add_amount(post, money, options)
82
+ add_invoice(post, options)
83
+ add_refund_specific_fields(post, authorization)
84
+
85
+ commit(post)
86
+ end
87
+
81
88
  private
82
89
 
83
90
  def new_request
@@ -95,40 +102,38 @@ module ActiveMerchant #:nodoc:
95
102
  end
96
103
 
97
104
  def add_invoice(post, options)
98
- requires!(options, :order_id)
99
-
100
- post[:ms] = options[:order_id] # "Merchant Session", must be unique per request
101
- post[:mo] = options[:invoice] # "Order Details", displayed in Paystation Admin
102
- post[:mr] = options[:description] # "Merchant Reference Code", seen from Paystation Admin
105
+ post[:ms] = options[:order_id] || generate_unique_id
106
+ post[:mo] = options[:invoice]
107
+ post[:mr] = options[:description]
103
108
  end
104
109
 
105
110
  def add_credit_card(post, credit_card)
106
-
107
111
  post[:cn] = credit_card.number
108
112
  post[:ct] = credit_card.brand
109
113
  post[:ex] = format_date(credit_card.month, credit_card.year)
110
114
  post[:cc] = credit_card.verification_value if credit_card.verification_value?
111
-
112
115
  end
113
116
 
114
- # bill a token (stored via "store") rather than a Credit Card
115
117
  def add_token(post, token)
116
118
  post[:fp] = "t" # turn on "future payments" - what paystation calls Token Billing
117
119
  post[:ft] = token
118
120
  end
119
121
 
120
122
  def store_credit_card(post, options)
121
-
122
123
  post[:fp] = "t" # turn on "future payments" - what paystation calls Token Billing
123
124
  post[:fs] = "t" # tells paystation to store right now, not bill
124
125
  post[:ft] = options[:token] if options[:token] # specify a token to use that, or let Paystation generate one
125
-
126
126
  end
127
127
 
128
128
  def add_authorize_flag(post, options)
129
129
  post[:pa] = "t" # tells Paystation that this is a pre-auth authorisation payment (account must be in pre-auth mode)
130
130
  end
131
131
 
132
+ def add_refund_specific_fields(post, authorization)
133
+ post[:rc] = "t"
134
+ post[:rt] = authorization
135
+ end
136
+
132
137
  def add_authorization_token(post, auth_token, verification_value = nil)
133
138
  post[:cp] = "t" # Capture Payment flag – tells Paystation this transaction should be treated as a capture payment
134
139
  post[:cx] = auth_token
@@ -136,10 +141,8 @@ module ActiveMerchant #:nodoc:
136
141
  end
137
142
 
138
143
  def add_amount(post, money, options)
139
-
140
144
  post[:am] = amount(money)
141
145
  post[:cu] = options[:currency] || currency(money)
142
-
143
146
  end
144
147
 
145
148
  def parse(xml_response)
@@ -147,8 +150,6 @@ module ActiveMerchant #:nodoc:
147
150
 
148
151
  xml = REXML::Document.new(xml_response)
149
152
 
150
- # for normal payments, the root node is <Response>
151
- # for "future payments", it's <PaystationFuturePaymentResponse>
152
153
  xml.elements.each("#{xml.root.name}/*") do |element|
153
154
  response[element.name.underscore.to_sym] = element.text
154
155
  end
@@ -157,12 +158,9 @@ module ActiveMerchant #:nodoc:
157
158
  end
158
159
 
159
160
  def commit(post)
160
-
161
- post[:tm] = "T" if test? # test mode
162
-
161
+ post[:tm] = "T" if test?
163
162
  pstn_prefix_params = post.collect { |key, value| "pstn_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
164
163
 
165
- # need include paystation param as "initiator flag for payment engine"
166
164
  data = ssl_post(self.live_url, "#{pstn_prefix_params}&paystation=_empty")
167
165
  response = parse(data)
168
166
  message = message_from(response)
@@ -188,8 +186,6 @@ module ActiveMerchant #:nodoc:
188
186
  end
189
187
 
190
188
  class PaystationResponse < Response
191
- # add a method to response so we can easily get the token
192
- # for Validate transactions
193
189
  def token
194
190
  @params["future_payment_token"]
195
191
  end
@@ -192,6 +192,10 @@ module ActiveMerchant #:nodoc:
192
192
  end
193
193
 
194
194
  top
195
+ rescue JSON::ParserError
196
+ {
197
+ "error" => "Invalid response received from the PayU API. (The raw response was `#{body}`)."
198
+ }
195
199
  end
196
200
 
197
201
  def commit(url, parameters)
@@ -38,10 +38,10 @@ module ActiveMerchant #:nodoc:
38
38
  self.display_name = "Redsys"
39
39
 
40
40
  CURRENCY_CODES = {
41
- "ARS" => '032',
42
- "AUD" => '036',
41
+ "ARS" => '32',
42
+ "AUD" => '36',
43
43
  "BRL" => '986',
44
- "BOB" => '068',
44
+ "BOB" => '68',
45
45
  "CAD" => '124',
46
46
  "CHF" => '756',
47
47
  "CLP" => '152',
@@ -50,6 +50,7 @@ module ActiveMerchant #:nodoc:
50
50
  "GBP" => '826',
51
51
  "GTQ" => '320',
52
52
  "JPY" => '392',
53
+ "MYR" => '458',
53
54
  "MXN" => '484',
54
55
  "NZD" => '554',
55
56
  "PEN" => '604',
@@ -88,9 +88,9 @@ module ActiveMerchant #:nodoc:
88
88
 
89
89
  def scrub(transcript)
90
90
  transcript.
91
- gsub(%r((pwd=).+(/>))i, '\1[FILTERED]\2').
92
- gsub(%r((<Number>).+(</Number>))i, '\1[FILTERED]\2').
93
- gsub(%r((<Verification>).+(</Verification>))i, '\1[FILTERED]\2')
91
+ gsub(%r((pwd=).+?(/>))i, '\1[FILTERED]\2').
92
+ gsub(%r((<Number>).+?(</Number>))i, '\1[FILTERED]\2').
93
+ gsub(%r((<Verification>).+?(</Verification>))i, '\1[FILTERED]\2')
94
94
  end
95
95
 
96
96
  private
@@ -120,25 +120,23 @@ module ActiveMerchant #:nodoc:
120
120
  end
121
121
  end
122
122
 
123
- def credit(money, source, options = {})
124
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
125
- refund(money, source, options)
126
- end
127
-
128
- # Performs a refund transaction.
129
123
  #
130
124
  # ==== Parameters
131
125
  #
132
126
  # * <tt>money</tt> - The amount to be authorized as an integer value in cents.
133
- # * <tt>source</tt> - The CreditCard or Check object to be used as the target for the refund.
134
- def refund(money, source, options = {})
127
+ # * <tt>source</tt> - The CreditCard or Check object to be used as the target for the credit.
128
+ def credit(money, source, options = {})
135
129
  if card_brand(source) == "check"
136
- virtual_check.refund(money, source, options)
130
+ virtual_check.credit(money, source, options)
137
131
  else
138
- bankcard.refund(money, source, options)
132
+ bankcard.credit(money, source, options)
139
133
  end
140
134
  end
141
135
 
136
+ def refund(money, reference, options={})
137
+ bankcard.refund(money, reference, options)
138
+ end
139
+
142
140
  # Stores a credit card in the Sage vault.
143
141
  #
144
142
  # ==== Parameters
@@ -47,17 +47,19 @@ module ActiveMerchant #:nodoc:
47
47
  end
48
48
 
49
49
  def credit(money, credit_card, options = {})
50
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
51
- refund(money, credit_card, options)
52
- end
53
-
54
- def refund(money, credit_card, options = {})
55
50
  post = {}
56
51
  add_credit_card(post, credit_card)
57
52
  add_transaction_data(post, money, options)
58
53
  commit(:credit, post)
59
54
  end
60
55
 
56
+ def refund(money, reference, options={})
57
+ post = {}
58
+ add_reference(post, reference)
59
+ add_transaction_data(post, money, options)
60
+ commit(:refund, post)
61
+ end
62
+
61
63
  private
62
64
 
63
65
  def add_credit_card(post, credit_card)
@@ -20,7 +20,8 @@ module ActiveMerchant #:nodoc:
20
20
  :authorization => '02',
21
21
  :capture => '11',
22
22
  :void => '04',
23
- :credit => '06'
23
+ :credit => '06',
24
+ :refund => '10'
24
25
  }
25
26
 
26
27
  def initialize(options = {})
@@ -30,7 +31,7 @@ module ActiveMerchant #:nodoc:
30
31
 
31
32
  private
32
33
  def add_invoice(post, options)
33
- post[:T_ordernum] = options[:order_id].slice(0, 20)
34
+ post[:T_ordernum] = (options[:order_id] || generate_unique_id).slice(0, 20)
34
35
  post[:T_tax] = amount(options[:tax]) unless options[:tax].blank?
35
36
  post[:T_shipping] = amount(options[:shipping]) unless options[:shipping].blank?
36
37
  end
@@ -22,11 +22,6 @@ module ActiveMerchant #:nodoc:
22
22
  end
23
23
 
24
24
  def credit(money, credit_card, options = {})
25
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
26
- refund(money, source, options)
27
- end
28
-
29
- def refund(money, credit_card, options = {})
30
25
  post = {}
31
26
  add_check(post, credit_card)
32
27
  add_check_customer_data(post, options)
@@ -42,6 +42,7 @@ module ActiveMerchant #:nodoc:
42
42
  'incorrect_cvc' => STANDARD_ERROR_CODE[:incorrect_cvc],
43
43
  'incorrect_zip' => STANDARD_ERROR_CODE[:incorrect_zip],
44
44
  'card_declined' => STANDARD_ERROR_CODE[:card_declined],
45
+ 'call_issuer' => STANDARD_ERROR_CODE[:call_issuer],
45
46
  'processing_error' => STANDARD_ERROR_CODE[:processing_error]
46
47
  }
47
48
 
@@ -123,7 +124,7 @@ module ActiveMerchant #:nodoc:
123
124
 
124
125
  def verify(payment, options = {})
125
126
  MultiResponse.run(:use_first_response) do |r|
126
- r.process { authorize(50, payment, options.merge(currency: "USD")) }
127
+ r.process { authorize(50, payment, options) }
127
128
  r.process(:ignore_result) { void(r.authorization, options) }
128
129
  end
129
130
  end
@@ -222,6 +223,10 @@ module ActiveMerchant #:nodoc:
222
223
  gsub(%r((&?three_d_secure\[cryptogram\]=)[\w=]*(&?)), '\1[FILTERED]\2')
223
224
  end
224
225
 
226
+ def supports_network_tokenization?
227
+ true
228
+ end
229
+
225
230
  private
226
231
 
227
232
  class StripePaymentToken < PaymentToken
@@ -295,6 +300,11 @@ module ActiveMerchant #:nodoc:
295
300
  card = {}
296
301
  if emv_payment?(creditcard)
297
302
  add_emv_creditcard(post, creditcard.icc_data)
303
+ post[:card][:read_method] = "contactless" if creditcard.contactless
304
+ if creditcard.encrypted_pin_cryptogram.present? && creditcard.encrypted_pin_ksn.present?
305
+ post[:card][:encrypted_pin] = creditcard.encrypted_pin_cryptogram
306
+ post[:card][:encrypted_pin_key_id] = creditcard.encrypted_pin_ksn
307
+ end
298
308
  elsif creditcard.respond_to?(:number)
299
309
  if creditcard.respond_to?(:track_data) && creditcard.track_data.present?
300
310
  card[:swipe_data] = creditcard.track_data
@@ -418,7 +428,7 @@ module ActiveMerchant #:nodoc:
418
428
 
419
429
  success = !response.key?("error")
420
430
 
421
- card = response["card"] || response["active_card"] || response["source"] || {}
431
+ card = card_from_response(response)
422
432
  avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"]
423
433
  cvc_code = CVC_CODE_TRANSLATOR[card["cvc_check"]]
424
434
 
@@ -429,8 +439,8 @@ module ActiveMerchant #:nodoc:
429
439
  :authorization => success ? response["id"] : response["error"]["charge"],
430
440
  :avs_result => { :code => avs_code },
431
441
  :cvv_result => cvc_code,
432
- :emv_authorization => card["emv_auth_data"],
433
- :error_code => success ? nil : STANDARD_ERROR_CODE_MAPPING[response["error"]["code"]]
442
+ :emv_authorization => emv_authorization_from_response(response),
443
+ :error_code => success ? nil : error_code_from(response)
434
444
  )
435
445
  end
436
446
 
@@ -459,6 +469,25 @@ module ActiveMerchant #:nodoc:
459
469
  def emv_payment?(payment)
460
470
  payment.respond_to?(:emv?) && payment.emv?
461
471
  end
472
+
473
+ def card_from_response(response)
474
+ response["card"] || response["active_card"] || response["source"] || {}
475
+ end
476
+
477
+ def emv_authorization_from_response(response)
478
+ return response["error"]["emv_auth_data"] if response["error"]
479
+
480
+ card_from_response(response)["emv_auth_data"]
481
+ end
482
+
483
+ def error_code_from(response)
484
+ code = response['error']['code']
485
+ decline_code = response['error']['decline_code'] if code == 'card_declined'
486
+
487
+ error_code = STANDARD_ERROR_CODE_MAPPING[decline_code]
488
+ error_code ||= STANDARD_ERROR_CODE_MAPPING[code]
489
+ error_code
490
+ end
462
491
  end
463
492
  end
464
493
  end
@@ -73,27 +73,34 @@ module ActiveMerchant #:nodoc:
73
73
  post = {}
74
74
  post[:client_id] = @options[:client_id]
75
75
  post[:user_name] = "#{creditcard.first_name} #{creditcard.last_name}"
76
- post[:email] = options[:email]
76
+ post[:email] = options[:email] || "unspecified@example.com"
77
77
  post[:cc_number] = creditcard.number
78
- post[:cvv] = creditcard.verification_value
79
- post[:expiration_month] = creditcard.month
80
- post[:expiration_year] = creditcard.year
78
+ post[:cvv] = creditcard.verification_value unless options[:recurring]
79
+ post[:expiration_month] = "#{creditcard.month}"
80
+ post[:expiration_year] = "#{creditcard.year}"
81
81
  post[:original_ip] = options[:ip] if options[:ip]
82
82
  post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint]
83
83
  if(billing_address = (options[:billing_address] || options[:address]))
84
84
  post[:address] = {
85
85
  "address1" => billing_address[:address1],
86
86
  "city" => billing_address[:city],
87
- "state" => billing_address[:state],
88
87
  "country" => billing_address[:country]
89
88
  }
90
89
  if(post[:country] == "US")
91
90
  post[:address]["zip"] = billing_address[:zip]
91
+ post[:address]["state"] = billing_address[:state]
92
92
  else
93
+ post[:address]["region"] = billing_address[:state]
93
94
  post[:address]["postcode"] = billing_address[:zip]
94
95
  end
95
96
  end
96
- commit('/credit_card/create', post)
97
+
98
+ if options[:recurring] == true
99
+ post[:client_secret] = @options[:client_secret]
100
+ commit('/credit_card/transfer', post)
101
+ else
102
+ commit('/credit_card/create', post)
103
+ end
97
104
  end
98
105
 
99
106
  private
@@ -22,7 +22,6 @@ module ActiveMerchant #:nodoc:
22
22
 
23
23
  def authorize(money, credit_card, options={})
24
24
  response = create_token(true, credit_card.first_name+' '+credit_card.last_name, credit_card.month, credit_card.year, credit_card.number, credit_card.verification_value)
25
-
26
25
  if response.success?
27
26
  options[:authorizeOnly] = true
28
27
  post = create_post_for_auth_or_purchase(response.authorization, money, options)
@@ -95,7 +94,7 @@ module ActiveMerchant #:nodoc:
95
94
  def create_post_for_auth_or_purchase(token, money, options)
96
95
  {
97
96
  "token" => token,
98
- "orderDescription" => options[:description],
97
+ "orderDescription" => options[:description] || 'Worldpay Order',
99
98
  "amount" => money,
100
99
  "currencyCode" => options[:currency] || default_currency,
101
100
  "name" => options[:billing_address]&&options[:billing_address][:name] ? options[:billing_address][:name] : '',
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.50.0"
2
+ VERSION = "1.51.0"
3
3
  end