activemerchant 1.62.0 → 1.79.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +420 -2
  3. data/README.md +1 -2
  4. data/lib/active_merchant/billing/credit_card.rb +13 -14
  5. data/lib/active_merchant/billing/credit_card_methods.rb +3 -1
  6. data/lib/active_merchant/billing/gateway.rb +25 -9
  7. data/lib/active_merchant/billing/gateways/adyen.rb +299 -0
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +168 -56
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +4 -2
  10. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +65 -22
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +87 -7
  12. data/lib/active_merchant/billing/gateways/beanstream.rb +2 -0
  13. data/lib/active_merchant/billing/gateways/blue_snap.rb +3 -8
  14. data/lib/active_merchant/billing/gateways/borgun.rb +10 -10
  15. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +1 -0
  16. data/lib/active_merchant/billing/gateways/braintree_blue.rb +49 -15
  17. data/lib/active_merchant/billing/gateways/card_connect.rb +286 -0
  18. data/lib/active_merchant/billing/gateways/card_stream.rb +97 -2
  19. data/lib/active_merchant/billing/gateways/cardprocess.rb +254 -0
  20. data/lib/active_merchant/billing/gateways/cashnet.rb +14 -2
  21. data/lib/active_merchant/billing/gateways/cenpos.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/checkout.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/checkout_v2.rb +44 -14
  24. data/lib/active_merchant/billing/gateways/citrus_pay.rb +0 -1
  25. data/lib/active_merchant/billing/gateways/clearhaus.rb +0 -2
  26. data/lib/active_merchant/billing/gateways/conekta.rb +4 -4
  27. data/lib/active_merchant/billing/gateways/creditcall.rb +71 -9
  28. data/lib/active_merchant/billing/gateways/credorax.rb +117 -5
  29. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  30. data/lib/active_merchant/billing/gateways/cyber_source.rb +54 -15
  31. data/lib/active_merchant/billing/gateways/data_cash.rb +12 -0
  32. data/lib/active_merchant/billing/gateways/dibs.rb +0 -1
  33. data/lib/active_merchant/billing/gateways/digitzs.rb +292 -0
  34. data/lib/active_merchant/billing/gateways/ebanx.rb +296 -0
  35. data/lib/active_merchant/billing/gateways/elavon.rb +37 -95
  36. data/lib/active_merchant/billing/gateways/element.rb +11 -1
  37. data/lib/active_merchant/billing/gateways/fat_zebra.rb +3 -29
  38. data/lib/active_merchant/billing/gateways/first_pay.rb +12 -10
  39. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +37 -20
  40. data/lib/active_merchant/billing/gateways/forte.rb +0 -1
  41. data/lib/active_merchant/billing/gateways/global_collect.rb +55 -16
  42. data/lib/active_merchant/billing/gateways/global_transport.rb +16 -2
  43. data/lib/active_merchant/billing/gateways/hps.rb +12 -1
  44. data/lib/active_merchant/billing/gateways/iats_payments.rb +2 -2
  45. data/lib/active_merchant/billing/gateways/iveri.rb +251 -0
  46. data/lib/active_merchant/billing/gateways/jetpay.rb +12 -9
  47. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +437 -0
  48. data/lib/active_merchant/billing/gateways/kushki.rb +227 -0
  49. data/lib/active_merchant/billing/gateways/linkpoint.rb +2 -2
  50. data/lib/active_merchant/billing/gateways/litle.rb +107 -30
  51. data/lib/active_merchant/billing/gateways/mercado_pago.rb +262 -0
  52. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +11 -0
  53. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +16 -4
  54. data/lib/active_merchant/billing/gateways/mercury.rb +14 -1
  55. data/lib/active_merchant/billing/gateways/migs.rb +28 -6
  56. data/lib/active_merchant/billing/gateways/moneris.rb +20 -12
  57. data/lib/active_merchant/billing/gateways/moneris_us.rb +11 -0
  58. data/lib/active_merchant/billing/gateways/mundipagg.rb +292 -0
  59. data/lib/active_merchant/billing/gateways/nab_transact.rb +4 -4
  60. data/lib/active_merchant/billing/gateways/netbanx.rb +60 -16
  61. data/lib/active_merchant/billing/gateways/netbilling.rb +0 -1
  62. data/lib/active_merchant/billing/gateways/nmi.rb +12 -1
  63. data/lib/active_merchant/billing/gateways/ogone.rb +1 -1
  64. data/lib/active_merchant/billing/gateways/omise.rb +9 -5
  65. data/lib/active_merchant/billing/gateways/openpay.rb +13 -0
  66. data/lib/active_merchant/billing/gateways/opp.rb +124 -114
  67. data/lib/active_merchant/billing/gateways/optimal_payment.rb +14 -1
  68. data/lib/active_merchant/billing/gateways/orbital.rb +83 -14
  69. data/lib/active_merchant/billing/gateways/pay_hub.rb +2 -2
  70. data/lib/active_merchant/billing/gateways/payeezy.rb +152 -46
  71. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -2
  72. data/lib/active_merchant/billing/gateways/payflow.rb +24 -2
  73. data/lib/active_merchant/billing/gateways/payment_express.rb +3 -2
  74. data/lib/active_merchant/billing/gateways/paymentez.rb +276 -0
  75. data/lib/active_merchant/billing/gateways/paymill.rb +18 -10
  76. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +14 -0
  77. data/lib/active_merchant/billing/gateways/paypal.rb +0 -12
  78. data/lib/active_merchant/billing/gateways/paystation.rb +14 -1
  79. data/lib/active_merchant/billing/gateways/payu_latam.rb +102 -62
  80. data/lib/active_merchant/billing/gateways/pin.rb +5 -0
  81. data/lib/active_merchant/billing/gateways/pro_pay.rb +326 -0
  82. data/lib/active_merchant/billing/gateways/psigate.rb +12 -1
  83. data/lib/active_merchant/billing/gateways/qbms.rb +11 -0
  84. data/lib/active_merchant/billing/gateways/quickbooks.rb +10 -0
  85. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +21 -17
  86. data/lib/active_merchant/billing/gateways/quickpay.rb +3 -3
  87. data/lib/active_merchant/billing/gateways/qvalent.rb +60 -3
  88. data/lib/active_merchant/billing/gateways/realex.rb +16 -6
  89. data/lib/active_merchant/billing/gateways/redsys.rb +8 -2
  90. data/lib/active_merchant/billing/gateways/safe_charge.rb +262 -0
  91. data/lib/active_merchant/billing/gateways/sage.rb +8 -3
  92. data/lib/active_merchant/billing/gateways/sage_pay.rb +29 -13
  93. data/lib/active_merchant/billing/gateways/secure_net.rb +11 -1
  94. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -0
  95. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  96. data/lib/active_merchant/billing/gateways/spreedly_core.rb +53 -7
  97. data/lib/active_merchant/billing/gateways/stripe.rb +84 -26
  98. data/lib/active_merchant/billing/gateways/tns.rb +0 -1
  99. data/lib/active_merchant/billing/gateways/trans_first.rb +3 -2
  100. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +61 -26
  101. data/lib/active_merchant/billing/gateways/trexle.rb +217 -0
  102. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +114 -9
  103. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +45 -22
  104. data/lib/active_merchant/billing/gateways/vanco.rb +1 -1
  105. data/lib/active_merchant/billing/gateways/wepay.rb +79 -46
  106. data/lib/active_merchant/billing/gateways/wirecard.rb +5 -4
  107. data/lib/active_merchant/billing/gateways/worldpay.rb +85 -20
  108. data/lib/active_merchant/billing/gateways/worldpay_us.rb +27 -8
  109. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  110. data/lib/active_merchant/connection.rb +48 -12
  111. data/lib/active_merchant/net_http_ssl_connection.rb +9 -0
  112. data/lib/active_merchant/network_connection_retries.rb +6 -4
  113. data/lib/active_merchant/posts_data.rb +11 -1
  114. data/lib/active_merchant/version.rb +1 -1
  115. data/lib/active_merchant.rb +2 -5
  116. data/lib/certs/cacert.pem +85 -0
  117. data/lib/support/ssl_version.rb +87 -0
  118. metadata +25 -9
  119. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +0 -314
@@ -16,7 +16,8 @@ module ActiveMerchant #:nodoc:
16
16
  :capture => 'cc:capture',
17
17
  :refund => 'cc:refund',
18
18
  :void => 'cc:void',
19
- :void_release => 'cc:void:release'
19
+ :void_release => 'cc:void:release',
20
+ :check_purchase => 'check:sale'
20
21
  }
21
22
 
22
23
  STANDARD_ERROR_CODE_MAPPING = {
@@ -48,7 +49,7 @@ module ActiveMerchant #:nodoc:
48
49
 
49
50
  add_amount(post, money)
50
51
  add_invoice(post, options)
51
- add_credit_card(post, credit_card)
52
+ add_payment(post, credit_card)
52
53
  unless credit_card.track_data.present?
53
54
  add_address(post, credit_card, options)
54
55
  add_customer_data(post, options)
@@ -59,20 +60,20 @@ module ActiveMerchant #:nodoc:
59
60
  commit(:authorization, post)
60
61
  end
61
62
 
62
- def purchase(money, credit_card, options = {})
63
+ def purchase(money, payment, options = {})
63
64
  post = {}
64
65
 
65
66
  add_amount(post, money)
66
67
  add_invoice(post, options)
67
- add_credit_card(post, credit_card)
68
- unless credit_card.track_data.present?
69
- add_address(post, credit_card, options)
68
+ add_payment(post, payment)
69
+ unless payment.respond_to?(:track_data) && payment.track_data.present?
70
+ add_address(post, payment, options)
70
71
  add_customer_data(post, options)
71
72
  end
72
73
  add_split_payments(post, options)
73
74
  add_test_mode(post, options)
74
75
 
75
- commit(:purchase, post)
76
+ payment.respond_to?(:routing_number) ? commit(:check_purchase, post) : commit(:purchase, post)
76
77
  end
77
78
 
78
79
  def capture(money, authorization, options = {})
@@ -106,6 +107,19 @@ module ActiveMerchant #:nodoc:
106
107
  commit(command, post)
107
108
  end
108
109
 
110
+ def supports_scrubbing?
111
+ true
112
+ end
113
+
114
+ def scrub(transcript)
115
+ transcript.
116
+ gsub(%r((&?UMcard=)\d*(&?))i, '\1[FILTERED]\2').
117
+ gsub(%r((&?UMcvv2=)\d*(&?))i, '\1[FILTERED]\2').
118
+ gsub(%r((&?UMmagstripe=)[^&]*)i, '\1[FILTERED]\2').
119
+ gsub(%r((&?UMaccount=)[^&]*)i, '\1[FILTERED]').
120
+ gsub(%r((&?UMkey=)[^&]*)i, '\1[FILTERED]')
121
+ end
122
+
109
123
  private
110
124
 
111
125
  def add_amount(post, money)
@@ -126,7 +140,12 @@ module ActiveMerchant #:nodoc:
126
140
 
127
141
  if options.has_key? :email
128
142
  post[:custemail] = options[:email]
129
- post[:custreceipt] = 'No'
143
+ if options[:cust_receipt]
144
+ post[:custreceipt] = options[:cust_receipt]
145
+ post[:custreceiptname] = options[:cust_receipt_name] if options[:cust_receipt_name]
146
+ else
147
+ post[:custreceipt] = 'No'
148
+ end
130
149
  end
131
150
 
132
151
  if options.has_key? :customer
@@ -138,19 +157,19 @@ module ActiveMerchant #:nodoc:
138
157
  end
139
158
  end
140
159
 
141
- def add_address(post, credit_card, options)
160
+ def add_address(post, payment, options)
142
161
  billing_address = options[:billing_address] || options[:address]
143
162
 
144
- add_address_for_type(:billing, post, credit_card, billing_address) if billing_address
145
- add_address_for_type(:shipping, post, credit_card, options[:shipping_address]) if options[:shipping_address]
163
+ add_address_for_type(:billing, post, payment, billing_address) if billing_address
164
+ add_address_for_type(:shipping, post, payment, options[:shipping_address]) if options[:shipping_address]
146
165
  end
147
166
 
148
- def add_address_for_type(type, post, credit_card, address)
167
+ def add_address_for_type(type, post, payment, address)
149
168
  prefix = address_key_prefix(type)
150
169
  first_name, last_name = split_names(address[:name])
151
170
 
152
- post[address_key(prefix, 'fname')] = first_name.blank? && last_name.blank? ? credit_card.first_name : first_name
153
- post[address_key(prefix, 'lname')] = first_name.blank? && last_name.blank? ? credit_card.last_name : last_name
171
+ post[address_key(prefix, 'fname')] = first_name.blank? && last_name.blank? ? payment.first_name : first_name
172
+ post[address_key(prefix, 'lname')] = first_name.blank? && last_name.blank? ? payment.last_name : last_name
154
173
  post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank?
155
174
  post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank?
156
175
  post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank?
@@ -177,16 +196,20 @@ module ActiveMerchant #:nodoc:
177
196
  post[:description] = options[:description]
178
197
  end
179
198
 
180
- def add_credit_card(post, credit_card)
181
- if credit_card.track_data.present?
182
- post[:magstripe] = credit_card.track_data
199
+ def add_payment(post, payment)
200
+ if payment.respond_to?(:routing_number)
201
+ post[:account] = payment.account_number
202
+ post[:routing] = payment.routing_number
203
+ post[:name] = payment.name unless payment.name.blank?
204
+ elsif payment.respond_to?(:track_data) && payment.track_data.present?
205
+ post[:magstripe] = payment.track_data
183
206
  post[:cardpresent] = true
184
207
  else
185
- post[:card] = credit_card.number
186
- post[:cvv2] = credit_card.verification_value if credit_card.verification_value?
187
- post[:expir] = expdate(credit_card)
188
- post[:name] = credit_card.name unless credit_card.name.blank?
189
- post[:cardpresent] = true if credit_card.manual_entry
208
+ post[:card] = payment.number
209
+ post[:cvv2] = payment.verification_value if payment.verification_value?
210
+ post[:expir] = expdate(payment)
211
+ post[:name] = payment.name unless payment.name.blank?
212
+ post[:cardpresent] = true if payment.manual_entry
190
213
  end
191
214
  end
192
215
 
@@ -5,7 +5,7 @@ module ActiveMerchant
5
5
  class VancoGateway < Gateway
6
6
  include Empty
7
7
 
8
- self.test_url = 'https://www.vancodev.com/cgi-bin/wstest2.vps'
8
+ self.test_url = 'https://uat.vancopayments.com/cgi-bin/ws2.vps'
9
9
  self.live_url = 'https://myvanco.vancopayments.com/cgi-bin/ws2.vps'
10
10
 
11
11
  self.supported_countries = ['US']
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  self.test_url = 'https://stage.wepayapi.com/v2'
5
5
  self.live_url = 'https://wepayapi.com/v2'
6
6
 
7
- self.supported_countries = ['US']
7
+ self.supported_countries = ['US', 'CA']
8
8
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
9
9
  self.homepage_url = 'https://www.wepay.com/'
10
10
  self.default_currency = 'USD'
@@ -18,38 +18,47 @@ module ActiveMerchant #:nodoc:
18
18
  def purchase(money, payment_method, options = {})
19
19
  post = {}
20
20
  if payment_method.is_a?(String)
21
- purchase_with_token(post, money, payment_method, options)
21
+ MultiResponse.run do |r|
22
+ r.process { authorize_with_token(post, money, payment_method, options) }
23
+ r.process { capture(money, r.authorization, options) }
24
+ end
22
25
  else
23
26
  MultiResponse.run do |r|
24
27
  r.process { store(payment_method, options) }
25
- r.process { purchase_with_token(post, money, split_authorization(r.authorization).first, options) }
28
+ r.process { authorize_with_token(post, money, r.authorization, options) }
29
+ r.process { capture(money, r.authorization, options) }
26
30
  end
27
31
  end
28
32
  end
29
33
 
30
34
  def authorize(money, payment_method, options = {})
31
- post = {auto_capture: 0}
35
+ post = {}
32
36
  if payment_method.is_a?(String)
33
- purchase_with_token(post, money, payment_method, options)
37
+ authorize_with_token(post, money, payment_method, options)
34
38
  else
35
39
  MultiResponse.run do |r|
36
40
  r.process { store(payment_method, options) }
37
- r.process { purchase_with_token(post, money, split_authorization(r.authorization).first, options) }
41
+ r.process { authorize_with_token(post, money, r.authorization, options) }
38
42
  end
39
43
  end
40
44
  end
41
45
 
42
46
  def capture(money, identifier, options = {})
47
+ checkout_id, original_amount = split_authorization(identifier)
48
+
43
49
  post = {}
44
- post[:checkout_id] = split_authorization(identifier).first
45
- commit('/checkout/capture', post)
50
+ post[:checkout_id] = checkout_id
51
+ if(money && (original_amount != amount(money)))
52
+ post[:amount] = amount(money)
53
+ end
54
+ commit('/checkout/capture', post, options)
46
55
  end
47
56
 
48
57
  def void(identifier, options = {})
49
58
  post = {}
50
59
  post[:checkout_id] = split_authorization(identifier).first
51
60
  post[:cancel_reason] = (options[:description] || "Void")
52
- commit('/checkout/cancel', post)
61
+ commit('/checkout/cancel', post, options)
53
62
  end
54
63
 
55
64
  def refund(money, identifier, options = {})
@@ -61,68 +70,70 @@ module ActiveMerchant #:nodoc:
61
70
  post[:amount] = amount(money)
62
71
  end
63
72
  post[:refund_reason] = (options[:description] || "Refund")
64
- post[:app_fee] = options[:application_fee] if options[:application_fee]
65
73
  post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message]
66
74
  post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message]
67
- commit("/checkout/refund", post)
75
+ commit("/checkout/refund", post, options)
68
76
  end
69
77
 
70
78
  def store(creditcard, options = {})
71
- requires!(options, :email)
72
-
73
79
  post = {}
74
80
  post[:client_id] = @options[:client_id]
75
81
  post[:user_name] = "#{creditcard.first_name} #{creditcard.last_name}"
76
82
  post[:email] = options[:email] || "unspecified@example.com"
77
83
  post[:cc_number] = creditcard.number
78
84
  post[:cvv] = creditcard.verification_value unless options[:recurring]
79
- post[:expiration_month] = "#{creditcard.month}"
80
- post[:expiration_year] = "#{creditcard.year}"
81
- post[:original_ip] = options[:ip] if options[:ip]
82
- post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint]
85
+ post[:expiration_month] = creditcard.month
86
+ post[:expiration_year] = creditcard.year
87
+
83
88
  if(billing_address = (options[:billing_address] || options[:address]))
84
- post[:address] = {
85
- "address1" => billing_address[:address1],
86
- "city" => billing_address[:city],
87
- "country" => billing_address[:country]
88
- }
89
- if(post[:country] == "US")
90
- post[:address]["zip"] = billing_address[:zip]
91
- post[:address]["state"] = billing_address[:state]
92
- else
93
- post[:address]["region"] = billing_address[:state]
94
- post[:address]["postcode"] = billing_address[:zip]
95
- end
89
+ post[:address] = {}
90
+ post[:address]["address1"] = billing_address[:address1] if billing_address[:address1]
91
+ post[:address]["city"] = billing_address[:city] if billing_address[:city]
92
+ post[:address]["country"] = billing_address[:country] if billing_address[:country]
93
+ post[:address]["region"] = billing_address[:state] if billing_address[:state]
94
+ post[:address]["postal_code"] = billing_address[:zip]
96
95
  end
97
96
 
98
97
  if options[:recurring] == true
99
98
  post[:client_secret] = @options[:client_secret]
100
- commit('/credit_card/transfer', post)
99
+ commit('/credit_card/transfer', post, options)
101
100
  else
102
- commit('/credit_card/create', post)
101
+ post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint]
102
+ post[:original_ip] = options[:ip] if options[:ip]
103
+ commit('/credit_card/create', post, options)
103
104
  end
104
105
  end
105
106
 
107
+ def supports_scrubbing?
108
+ true
109
+ end
110
+
111
+ def scrub(transcript)
112
+ transcript.
113
+ gsub(%r((\\?"cc_number\\?":\\?")[^\\"]+(\\?"))i, '\1[FILTERED]\2').
114
+ gsub(%r((\\?"cvv\\?":\\?")[^\\"]+(\\?"))i, '\1[FILTERED]\2').
115
+ gsub(%r((Authorization: Bearer )\w+)i, '\1[FILTERED]\2')
116
+ end
117
+
106
118
  private
107
119
 
108
- def purchase_with_token(post, money, token, options)
120
+ def authorize_with_token(post, money, token, options)
109
121
  add_token(post, token)
110
122
  add_product_data(post, money, options)
111
- commit('/checkout/create', post)
123
+ commit('/checkout/create', post, options)
112
124
  end
113
125
 
114
126
  def add_product_data(post, money, options)
115
127
  post[:account_id] = @options[:account_id]
116
128
  post[:amount] = amount(money)
117
129
  post[:short_description] = (options[:description] || "Purchase")
118
- post[:type] = (options[:type] || "GOODS")
130
+ post[:type] = (options[:type] || "goods")
119
131
  post[:currency] = (options[:currency] || currency(money))
120
132
  post[:long_description] = options[:long_description] if options[:long_description]
121
133
  post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message]
122
134
  post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message]
123
135
  post[:reference_id] = options[:order_id] if options[:order_id]
124
- post[:app_fee] = options[:application_fee] if options[:application_fee]
125
- post[:fee_payer] = options[:fee_payer] if options[:fee_payer]
136
+ post[:unique_id] = options[:unique_id] if options[:unique_id]
126
137
  post[:redirect_uri] = options[:redirect_uri] if options[:redirect_uri]
127
138
  post[:callback_uri] = options[:callback_uri] if options[:callback_uri]
128
139
  post[:fallback_uri] = options[:fallback_uri] if options[:fallback_uri]
@@ -133,11 +144,28 @@ module ActiveMerchant #:nodoc:
133
144
  post[:preapproval_id] = options[:preapproval_id] if options[:preapproval_id]
134
145
  post[:prefill_info] = options[:prefill_info] if options[:prefill_info]
135
146
  post[:funding_sources] = options[:funding_sources] if options[:funding_sources]
147
+ post[:payer_rbits] = options[:payer_rbits] if options[:payer_rbits]
148
+ post[:transaction_rbits] = options[:transaction_rbits] if options[:transaction_rbits]
149
+ add_fee(post, options)
136
150
  end
137
151
 
138
152
  def add_token(post, token)
139
- post[:payment_method_id] = token
140
- post[:payment_method_type] = "credit_card"
153
+ payment_method = {}
154
+ payment_method[:type] = "credit_card"
155
+ payment_method[:credit_card] = {
156
+ id: token,
157
+ auto_capture: false
158
+ }
159
+
160
+ post[:payment_method] = payment_method
161
+ end
162
+
163
+ def add_fee(post, options)
164
+ if options[:application_fee] || options[:fee_payer]
165
+ post[:fee] = {}
166
+ post[:fee][:app_fee] = options[:application_fee] if options[:application_fee]
167
+ post[:fee][:fee_payer] = options[:fee_payer] if options[:fee_payer]
168
+ end
141
169
  end
142
170
 
143
171
  def parse(response)
@@ -149,7 +177,7 @@ module ActiveMerchant #:nodoc:
149
177
  response = parse(ssl_post(
150
178
  ((test? ? test_url : live_url) + action),
151
179
  params.to_json,
152
- headers
180
+ headers(options)
153
181
  ))
154
182
  rescue ResponseError => e
155
183
  response = parse(e.response.body)
@@ -178,7 +206,8 @@ module ActiveMerchant #:nodoc:
178
206
  def authorization_from(response, params)
179
207
  return response["credit_card_id"].to_s if response["credit_card_id"]
180
208
 
181
- [response["checkout_id"], params[:amount]].join('|')
209
+ original_amount = response["amount"].nil? ? nil : sprintf("%0.02f", response["amount"])
210
+ [response["checkout_id"], original_amount].join('|')
182
211
  end
183
212
 
184
213
  def split_authorization(authorization)
@@ -192,14 +221,18 @@ module ActiveMerchant #:nodoc:
192
221
  return Response.new(false, message)
193
222
  end
194
223
 
195
- def headers
196
- {
197
- "Content-Type" => "application/json",
198
- "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
199
- "Authorization" => "Bearer #{@options[:access_token]}"
224
+ def headers(options)
225
+ headers = {
226
+ "Content-Type" => "application/json",
227
+ "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
228
+ "Authorization" => "Bearer #{@options[:access_token]}"
200
229
  }
230
+ headers["Api-Version"] = options[:version] if options[:version]
231
+ headers["Client-IP"] = options[:ip] if options[:ip]
232
+ headers["WePay-Risk-Token"] = options[:risk_token] if options[:risk_token]
233
+
234
+ headers
201
235
  end
202
236
  end
203
237
  end
204
238
  end
205
-
@@ -235,17 +235,18 @@ module ActiveMerchant #:nodoc:
235
235
  add_address(xml, options[:billing_address])
236
236
  when :capture, :bookback
237
237
  xml.tag! 'GuWID', options[:preauthorization]
238
- add_amount(xml, money)
238
+ add_amount(xml, money, options)
239
239
  when :reversal
240
240
  xml.tag! 'GuWID', options[:preauthorization]
241
241
  end
242
+ add_customer_data(xml, options)
242
243
  end
243
244
  end
244
245
  end
245
246
 
246
247
  # Includes the payment (amount, currency, country) to the transaction-xml
247
248
  def add_invoice(xml, money, options)
248
- add_amount(xml, money)
249
+ add_amount(xml, money, options)
249
250
  xml.tag! 'Currency', options[:currency] || currency(money)
250
251
  xml.tag! 'CountryCode', options[:billing_address][:country]
251
252
  xml.tag! 'RECURRING_TRANSACTION' do
@@ -254,8 +255,8 @@ module ActiveMerchant #:nodoc:
254
255
  end
255
256
 
256
257
  # Include the amount in the transaction-xml
257
- def add_amount(xml, money)
258
- xml.tag! 'Amount', amount(money)
258
+ def add_amount(xml, money, options)
259
+ xml.tag! 'Amount', localized_amount(money, options[:currency] || currency(money))
259
260
  end
260
261
 
261
262
  # Includes the credit-card data to the transaction-xml
@@ -6,9 +6,10 @@ module ActiveMerchant #:nodoc:
6
6
 
7
7
  self.default_currency = 'GBP'
8
8
  self.money_format = :cents
9
- self.supported_countries = %w(HK GB AU AD BE CH CY CZ DE DK ES FI FR GI GR HU IE IL IT LI LU MC MT NL NO NZ PL PT SE SG SI SM TR UM VA)
9
+ self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA)
10
10
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :laser, :switch]
11
11
  self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
12
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
12
13
  self.homepage_url = 'http://www.worldpay.com/'
13
14
  self.display_name = 'Worldpay Global'
14
15
 
@@ -54,22 +55,35 @@ module ActiveMerchant #:nodoc:
54
55
 
55
56
  def void(authorization, options = {})
56
57
  MultiResponse.run do |r|
57
- r.process{inquire_request(authorization, options, "AUTHORISED")}
58
+ r.process{inquire_request(authorization, options, "AUTHORISED")} unless options[:authorization_validated]
58
59
  r.process{cancel_request(authorization, options)}
59
60
  end
60
61
  end
61
62
 
62
63
  def refund(money, authorization, options = {})
63
- MultiResponse.run do |r|
64
- r.process{inquire_request(authorization, options, "CAPTURED", "SETTLED", "SETTLED_BY_MERCHANT")}
65
- r.process{refund_request(money, authorization, options)}
64
+ response = MultiResponse.run do |r|
65
+ r.process { inquire_request(authorization, options, "CAPTURED", "SETTLED", "SETTLED_BY_MERCHANT") }
66
+ r.process { refund_request(money, authorization, options) }
66
67
  end
68
+
69
+ return response if response.success?
70
+ return response unless options[:force_full_refund_if_unsettled]
71
+
72
+ void(authorization, options ) if response.params["last_event"] == "AUTHORISED"
73
+ end
74
+
75
+ # Credits only function on a Merchant ID/login/profile flagged for Payouts
76
+ # aka Credit Fund Transfers (CFT), whereas normal purchases, refunds,
77
+ # and other transactions should be performed on a normal eCom-flagged
78
+ # merchant ID.
79
+ def credit(money, payment_method, options = {})
80
+ credit_request(money, payment_method, options.merge(:credit => true))
67
81
  end
68
82
 
69
83
  def verify(credit_card, options={})
70
84
  MultiResponse.run(:use_first_response) do |r|
71
85
  r.process { authorize(100, credit_card, options) }
72
- r.process(:ignore_result) { void(r.authorization, options) }
86
+ r.process(:ignore_result) { void(r.authorization, options.merge(:authorization_validated => true)) }
73
87
  end
74
88
  end
75
89
 
@@ -87,23 +101,27 @@ module ActiveMerchant #:nodoc:
87
101
  private
88
102
 
89
103
  def authorize_request(money, payment_method, options)
90
- commit('authorize', build_authorization_request(money, payment_method, options), "AUTHORISED")
104
+ commit('authorize', build_authorization_request(money, payment_method, options), "AUTHORISED", options)
91
105
  end
92
106
 
93
107
  def capture_request(money, authorization, options)
94
- commit('capture', build_capture_request(money, authorization, options), :ok)
108
+ commit('capture', build_capture_request(money, authorization, options), :ok, options)
95
109
  end
96
110
 
97
111
  def cancel_request(authorization, options)
98
- commit('cancel', build_void_request(authorization, options), :ok)
112
+ commit('cancel', build_void_request(authorization, options), :ok, options)
99
113
  end
100
114
 
101
115
  def inquire_request(authorization, options, *success_criteria)
102
- commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria)
116
+ commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria, options)
103
117
  end
104
118
 
105
119
  def refund_request(money, authorization, options)
106
- commit('refund', build_refund_request(money, authorization, options), :ok)
120
+ commit('refund', build_refund_request(money, authorization, options), :ok, options)
121
+ end
122
+
123
+ def credit_request(money, payment_method, options)
124
+ commit('credit', build_authorization_request(money, payment_method, options), :ok, options)
107
125
  end
108
126
 
109
127
  def build_request
@@ -189,7 +207,7 @@ module ActiveMerchant #:nodoc:
189
207
  amount_hash = {
190
208
  :value => localized_amount(money, currency),
191
209
  'currencyCode' => currency,
192
- 'exponent' => non_fractional_currency?(currency) ? 0 : 2
210
+ 'exponent' => currency_exponent(currency)
193
211
  }
194
212
 
195
213
  if options[:debit_credit_indicator]
@@ -211,7 +229,7 @@ module ActiveMerchant #:nodoc:
211
229
  end
212
230
  end
213
231
  else
214
- xml.tag! 'paymentDetails' do
232
+ xml.tag! 'paymentDetails', credit_fund_transfer_attribute(options) do
215
233
  xml.tag! CARD_CODES[card_brand(payment_method)] do
216
234
  xml.tag! 'cardNumber', payment_method.number
217
235
  xml.tag! 'expiryDate' do
@@ -223,21 +241,30 @@ module ActiveMerchant #:nodoc:
223
241
 
224
242
  add_address(xml, (options[:billing_address] || options[:address]))
225
243
  end
226
- if options[:ip]
227
- xml.tag! 'session', 'shopperIPAddress' => options[:ip]
244
+ if options[:ip] && options[:session_id]
245
+ xml.tag! 'session', 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
246
+ else
247
+ xml.tag! 'session', 'shopperIPAddress' => options[:ip] if options[:ip]
248
+ xml.tag! 'session', 'id' => options[:session_id] if options[:session_id]
228
249
  end
229
250
  end
230
251
  end
231
252
  end
232
253
 
233
254
  def add_email(xml, options)
234
- return unless options[:email]
255
+ return unless options[:execute_threed] || options[:email]
235
256
  xml.tag! 'shopper' do
236
- xml.tag! 'shopperEmailAddress', options[:email]
257
+ xml.tag! 'shopperEmailAddress', options[:email] if options[:email]
258
+ xml.tag! 'browser' do
259
+ xml.tag! 'acceptHeader', options[:accept_header]
260
+ xml.tag! 'userAgentHeader', options[:user_agent]
261
+ end
237
262
  end
238
263
  end
239
264
 
240
265
  def add_address(xml, address)
266
+ return unless address
267
+
241
268
  address = address_with_defaults(address)
242
269
 
243
270
  xml.tag! 'cardAddress' do
@@ -298,9 +325,24 @@ module ActiveMerchant #:nodoc:
298
325
  raw
299
326
  end
300
327
 
301
- def commit(action, request, *success_criteria)
302
- xmr = ssl_post(url, request, 'Content-Type' => 'text/xml', 'Authorization' => encoded_credentials)
303
- raw = parse(action, xmr)
328
+ def headers(options)
329
+ headers = {
330
+ 'Content-Type' => 'text/xml',
331
+ 'Authorization' => encoded_credentials
332
+ }
333
+ if options[:cookie]
334
+ headers.merge!('Set-Cookie' => options[:cookie]) if options[:cookie]
335
+ end
336
+ headers
337
+ end
338
+
339
+ def commit(action, request, *success_criteria, options)
340
+ xml = ssl_post(url, request, headers(options))
341
+ raw = parse(action, xml)
342
+ if options[:execute_threed]
343
+ raw[:cookie] = @cookie
344
+ raw[:session_id] = options[:session_id]
345
+ end
304
346
  success, message = success_and_message_from(raw, success_criteria)
305
347
 
306
348
  Response.new(
@@ -323,6 +365,18 @@ module ActiveMerchant #:nodoc:
323
365
  test? ? self.test_url : self.live_url
324
366
  end
325
367
 
368
+ # Override the regular handle response so we can access the headers
369
+ # Set-Cookie value is needed for 3DS transactions
370
+ def handle_response(response)
371
+ case response.code.to_i
372
+ when 200...300
373
+ @cookie = response.response['Set-Cookie']
374
+ response.body
375
+ else
376
+ raise ResponseError.new(response)
377
+ end
378
+ end
379
+
326
380
  # success_criteria can be:
327
381
  # - a string or an array of strings (if one of many responses)
328
382
  # - An array of strings if one of many responses could be considered a
@@ -355,10 +409,21 @@ module ActiveMerchant #:nodoc:
355
409
  (pair ? pair.last : nil)
356
410
  end
357
411
 
412
+ def credit_fund_transfer_attribute(options)
413
+ return unless options[:credit]
414
+ {'action' => "REFUND"}
415
+ end
416
+
358
417
  def encoded_credentials
359
418
  credentials = "#{@options[:login]}:#{@options[:password]}"
360
419
  "Basic #{[credentials].pack('m').strip}"
361
420
  end
421
+
422
+ def currency_exponent(currency)
423
+ return 0 if non_fractional_currency?(currency)
424
+ return 3 if three_decimal_currency?(currency)
425
+ return 2
426
+ end
362
427
  end
363
428
  end
364
429
  end