activemerchant 1.133.0 → 1.137.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +240 -0
  3. data/lib/active_merchant/billing/check.rb +2 -2
  4. data/lib/active_merchant/billing/compatibility.rb +4 -4
  5. data/lib/active_merchant/billing/credit_card.rb +11 -8
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +59 -6
  8. data/lib/active_merchant/billing/gateway.rb +9 -0
  9. data/lib/active_merchant/billing/gateways/adyen.rb +162 -43
  10. data/lib/active_merchant/billing/gateways/airwallex.rb +26 -12
  11. data/lib/active_merchant/billing/gateways/alelo.rb +23 -5
  12. data/lib/active_merchant/billing/gateways/authorize_net.rb +43 -35
  13. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +10 -6
  14. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -3
  15. data/lib/active_merchant/billing/gateways/axcessms.rb +6 -2
  16. data/lib/active_merchant/billing/gateways/banwire.rb +4 -2
  17. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +7 -3
  18. data/lib/active_merchant/billing/gateways/blue_pay.rb +13 -5
  19. data/lib/active_merchant/billing/gateways/blue_snap.rb +5 -5
  20. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +65 -20
  21. data/lib/active_merchant/billing/gateways/braintree_blue.rb +226 -73
  22. data/lib/active_merchant/billing/gateways/braintree_orange.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/card_connect.rb +5 -2
  24. data/lib/active_merchant/billing/gateways/card_stream.rb +4 -6
  25. data/lib/active_merchant/billing/gateways/cashnet.rb +1 -1
  26. data/lib/active_merchant/billing/gateways/cecabank/cecabank_common.rb +36 -0
  27. data/lib/active_merchant/billing/gateways/cecabank/cecabank_json.rb +316 -0
  28. data/lib/active_merchant/billing/gateways/cecabank/cecabank_xml.rb +220 -0
  29. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -240
  30. data/lib/active_merchant/billing/gateways/checkout_v2.rb +238 -34
  31. data/lib/active_merchant/billing/gateways/commerce_hub.rb +63 -6
  32. data/lib/active_merchant/billing/gateways/credorax.rb +3 -5
  33. data/lib/active_merchant/billing/gateways/cyber_source.rb +185 -47
  34. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +102 -58
  35. data/lib/active_merchant/billing/gateways/d_local.rb +26 -15
  36. data/lib/active_merchant/billing/gateways/data_cash.rb +21 -17
  37. data/lib/active_merchant/billing/gateways/datatrans.rb +279 -0
  38. data/lib/active_merchant/billing/gateways/decidir.rb +53 -18
  39. data/lib/active_merchant/billing/gateways/decidir_plus.rb +4 -1
  40. data/lib/active_merchant/billing/gateways/deepstack.rb +382 -0
  41. data/lib/active_merchant/billing/gateways/ebanx.rb +40 -36
  42. data/lib/active_merchant/billing/gateways/efsnet.rb +6 -2
  43. data/lib/active_merchant/billing/gateways/elavon.rb +99 -33
  44. data/lib/active_merchant/billing/gateways/element.rb +36 -7
  45. data/lib/active_merchant/billing/gateways/epay.rb +6 -2
  46. data/lib/active_merchant/billing/gateways/evo_ca.rb +6 -2
  47. data/lib/active_merchant/billing/gateways/eway.rb +4 -2
  48. data/lib/active_merchant/billing/gateways/eway_managed.rb +6 -2
  49. data/lib/active_merchant/billing/gateways/exact.rb +6 -2
  50. data/lib/active_merchant/billing/gateways/fat_zebra.rb +31 -3
  51. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -2
  52. data/lib/active_merchant/billing/gateways/first_pay/first_pay_common.rb +15 -0
  53. data/lib/active_merchant/billing/gateways/first_pay/first_pay_json.rb +190 -0
  54. data/lib/active_merchant/billing/gateways/first_pay/first_pay_xml.rb +183 -0
  55. data/lib/active_merchant/billing/gateways/first_pay.rb +6 -172
  56. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -2
  57. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +7 -3
  58. data/lib/active_merchant/billing/gateways/flex_charge.rb +347 -0
  59. data/lib/active_merchant/billing/gateways/garanti.rb +4 -2
  60. data/lib/active_merchant/billing/gateways/global_collect.rb +45 -37
  61. data/lib/active_merchant/billing/gateways/hi_pay.rb +286 -0
  62. data/lib/active_merchant/billing/gateways/hps.rb +1 -1
  63. data/lib/active_merchant/billing/gateways/iats_payments.rb +7 -2
  64. data/lib/active_merchant/billing/gateways/inspire.rb +6 -4
  65. data/lib/active_merchant/billing/gateways/instapay.rb +7 -4
  66. data/lib/active_merchant/billing/gateways/ipg.rb +9 -5
  67. data/lib/active_merchant/billing/gateways/iridium.rb +15 -5
  68. data/lib/active_merchant/billing/gateways/itransact.rb +6 -2
  69. data/lib/active_merchant/billing/gateways/iveri.rb +3 -3
  70. data/lib/active_merchant/billing/gateways/ixopay.rb +2 -2
  71. data/lib/active_merchant/billing/gateways/jetpay.rb +4 -2
  72. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +4 -2
  73. data/lib/active_merchant/billing/gateways/kushki.rb +72 -12
  74. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -2
  75. data/lib/active_merchant/billing/gateways/litle.rb +33 -50
  76. data/lib/active_merchant/billing/gateways/mastercard.rb +4 -4
  77. data/lib/active_merchant/billing/gateways/maxipago.rb +2 -2
  78. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +8 -5
  79. data/lib/active_merchant/billing/gateways/merchant_ware.rb +11 -4
  80. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +11 -4
  81. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +19 -3
  82. data/lib/active_merchant/billing/gateways/mercury.rb +6 -2
  83. data/lib/active_merchant/billing/gateways/metrics_global.rb +8 -6
  84. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +1 -0
  85. data/lib/active_merchant/billing/gateways/migs.rb +6 -2
  86. data/lib/active_merchant/billing/gateways/mit.rb +8 -3
  87. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +18 -10
  88. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  89. data/lib/active_merchant/billing/gateways/moneris.rb +9 -3
  90. data/lib/active_merchant/billing/gateways/money_movers.rb +6 -2
  91. data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -4
  92. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -2
  93. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -3
  94. data/lib/active_merchant/billing/gateways/netbilling.rb +6 -2
  95. data/lib/active_merchant/billing/gateways/network_merchants.rb +6 -2
  96. data/lib/active_merchant/billing/gateways/nmi.rb +18 -6
  97. data/lib/active_merchant/billing/gateways/ogone.rb +6 -2
  98. data/lib/active_merchant/billing/gateways/openpay.rb +4 -2
  99. data/lib/active_merchant/billing/gateways/opp.rb +1 -2
  100. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -2
  101. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +1 -3
  102. data/lib/active_merchant/billing/gateways/orbital.rb +83 -24
  103. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +7 -4
  104. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +6 -2
  105. data/lib/active_merchant/billing/gateways/pay_hub.rb +4 -2
  106. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -2
  107. data/lib/active_merchant/billing/gateways/pay_secure.rb +6 -2
  108. data/lib/active_merchant/billing/gateways/pay_trace.rb +31 -18
  109. data/lib/active_merchant/billing/gateways/payeezy.rb +19 -8
  110. data/lib/active_merchant/billing/gateways/payex.rb +4 -2
  111. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  112. data/lib/active_merchant/billing/gateways/payflow.rb +1 -3
  113. data/lib/active_merchant/billing/gateways/payment_express.rb +8 -4
  114. data/lib/active_merchant/billing/gateways/paymentez.rb +23 -11
  115. data/lib/active_merchant/billing/gateways/paysafe.rb +12 -11
  116. data/lib/active_merchant/billing/gateways/payscout.rb +7 -4
  117. data/lib/active_merchant/billing/gateways/paystation.rb +7 -3
  118. data/lib/active_merchant/billing/gateways/payway.rb +6 -2
  119. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +2 -2
  120. data/lib/active_merchant/billing/gateways/pin.rb +22 -4
  121. data/lib/active_merchant/billing/gateways/plexo.rb +49 -10
  122. data/lib/active_merchant/billing/gateways/plugnpay.rb +6 -2
  123. data/lib/active_merchant/billing/gateways/priority.rb +6 -5
  124. data/lib/active_merchant/billing/gateways/psigate.rb +6 -2
  125. data/lib/active_merchant/billing/gateways/psl_card.rb +6 -2
  126. data/lib/active_merchant/billing/gateways/qbms.rb +6 -2
  127. data/lib/active_merchant/billing/gateways/quantum.rb +6 -2
  128. data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -5
  129. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -4
  130. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +6 -2
  131. data/lib/active_merchant/billing/gateways/rapyd.rb +148 -46
  132. data/lib/active_merchant/billing/gateways/reach.rb +11 -4
  133. data/lib/active_merchant/billing/gateways/redsys.rb +2 -10
  134. data/lib/active_merchant/billing/gateways/redsys_rest.rb +507 -0
  135. data/lib/active_merchant/billing/gateways/s5.rb +3 -3
  136. data/lib/active_merchant/billing/gateways/safe_charge.rb +36 -16
  137. data/lib/active_merchant/billing/gateways/sage.rb +12 -4
  138. data/lib/active_merchant/billing/gateways/sage_pay.rb +79 -5
  139. data/lib/active_merchant/billing/gateways/sallie_mae.rb +6 -2
  140. data/lib/active_merchant/billing/gateways/secure_net.rb +6 -2
  141. data/lib/active_merchant/billing/gateways/secure_pay.rb +8 -6
  142. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -4
  143. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +6 -2
  144. data/lib/active_merchant/billing/gateways/securion_pay.rb +24 -10
  145. data/lib/active_merchant/billing/gateways/shift4.rb +17 -20
  146. data/lib/active_merchant/billing/gateways/shift4_v2.rb +117 -0
  147. data/lib/active_merchant/billing/gateways/simetrik.rb +17 -11
  148. data/lib/active_merchant/billing/gateways/skip_jack.rb +6 -2
  149. data/lib/active_merchant/billing/gateways/smart_ps.rb +7 -4
  150. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +4 -2
  151. data/lib/active_merchant/billing/gateways/spreedly_core.rb +2 -4
  152. data/lib/active_merchant/billing/gateways/stripe.rb +53 -21
  153. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +199 -50
  154. data/lib/active_merchant/billing/gateways/sum_up.rb +223 -0
  155. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +4 -2
  156. data/lib/active_merchant/billing/gateways/telr.rb +3 -4
  157. data/lib/active_merchant/billing/gateways/trans_first.rb +1 -2
  158. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +8 -16
  159. data/lib/active_merchant/billing/gateways/transact_pro.rb +1 -1
  160. data/lib/active_merchant/billing/gateways/trust_commerce.rb +6 -2
  161. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -8
  162. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -2
  163. data/lib/active_merchant/billing/gateways/vanco.rb +2 -4
  164. data/lib/active_merchant/billing/gateways/vantiv_express.rb +587 -0
  165. data/lib/active_merchant/billing/gateways/verifi.rb +6 -2
  166. data/lib/active_merchant/billing/gateways/viaklix.rb +6 -2
  167. data/lib/active_merchant/billing/gateways/visanet_peru.rb +2 -2
  168. data/lib/active_merchant/billing/gateways/vpos.rb +3 -3
  169. data/lib/active_merchant/billing/gateways/wirecard.rb +7 -3
  170. data/lib/active_merchant/billing/gateways/wompi.rb +5 -0
  171. data/lib/active_merchant/billing/gateways/worldpay.rb +140 -73
  172. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +13 -10
  173. data/lib/active_merchant/billing/gateways/xpay.rb +242 -0
  174. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  175. data/lib/active_merchant/billing/response.rb +2 -2
  176. data/lib/active_merchant/connection.rb +3 -17
  177. data/lib/active_merchant/country.rb +1 -0
  178. data/lib/active_merchant/errors.rb +10 -0
  179. data/lib/active_merchant/version.rb +1 -1
  180. data/lib/support/gateway_support.rb +2 -2
  181. data/lib/support/ssl_verify.rb +4 -4
  182. data/lib/support/ssl_version.rb +6 -6
  183. metadata +30 -9
@@ -67,6 +67,7 @@ module ActiveMerchant #:nodoc:
67
67
  def verify(credit_card, options = {})
68
68
  post = {}
69
69
  post[:ReferenceId] = options[:reference_id] || generate_unique_id
70
+ post[:Flow] = 'direct'
70
71
  post[:MerchantId] = options[:merchant_id] || @credentials[:merchant_id]
71
72
  post[:StatementDescriptor] = options[:statement_descriptor] if options[:statement_descriptor]
72
73
  post[:CustomerId] = options[:customer_id] if options[:customer_id]
@@ -76,6 +77,7 @@ module ActiveMerchant #:nodoc:
76
77
  add_metadata(post, options[:metadata])
77
78
  add_amount(money, post, options)
78
79
  add_browser_details(post, options)
80
+ add_invoice_number(post, options)
79
81
 
80
82
  commit('/verify', post, options)
81
83
  end
@@ -90,7 +92,8 @@ module ActiveMerchant #:nodoc:
90
92
  gsub(%r(("Number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
91
93
  gsub(%r(("Cvc\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
92
94
  gsub(%r(("InvoiceNumber\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
93
- gsub(%r(("MerchantId\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
95
+ gsub(%r(("MerchantId\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
96
+ gsub(%r(("Cryptogram\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
94
97
  end
95
98
 
96
99
  private
@@ -105,12 +108,14 @@ module ActiveMerchant #:nodoc:
105
108
  post[:Installments] = options[:installments] if options[:installments]
106
109
  post[:StatementDescriptor] = options[:statement_descriptor] if options[:statement_descriptor]
107
110
  post[:CustomerId] = options[:customer_id] if options[:customer_id]
111
+ post[:Flow] = 'direct'
108
112
 
109
113
  add_payment_method(post, payment, options)
110
114
  add_items(post, options[:items])
111
115
  add_metadata(post, options[:metadata])
112
116
  add_amount(money, post, options)
113
117
  add_browser_details(post, options)
118
+ add_invoice_number(post, options)
114
119
  end
115
120
 
116
121
  def header(parameters = {})
@@ -186,21 +191,55 @@ module ActiveMerchant #:nodoc:
186
191
  post[:BrowserDetails][:IpAddress] = browser_details[:ip] if browser_details[:ip]
187
192
  end
188
193
 
194
+ def add_invoice_number(post, options)
195
+ post[:InvoiceNumber] = options[:invoice_number] if options[:invoice_number]
196
+ end
197
+
189
198
  def add_payment_method(post, payment, options)
190
- post[:paymentMethod] = {}
199
+ payment_method = build_payment_method(payment)
191
200
 
192
- if payment&.is_a?(CreditCard)
193
- post[:paymentMethod][:type] = 'card'
194
- post[:paymentMethod][:Card] = {}
195
- post[:paymentMethod][:Card][:Number] = payment.number
196
- post[:paymentMethod][:Card][:ExpMonth] = format(payment.month, :two_digits) if payment.month
197
- post[:paymentMethod][:Card][:ExpYear] = format(payment.year, :two_digits) if payment.year
198
- post[:paymentMethod][:Card][:Cvc] = payment.verification_value if payment.verification_value
201
+ if payment_method.present?
202
+ add_card_holder(payment_method[:NetworkToken] || payment_method[:Card], payment, options)
203
+ post[:paymentMethod] = payment_method
204
+ end
205
+ end
199
206
 
200
- add_card_holder(post[:paymentMethod][:Card], payment, options)
207
+ def build_payment_method(payment)
208
+ case payment
209
+ when NetworkTokenizationCreditCard
210
+ {
211
+ source: 'network-token',
212
+ id: payment.brand,
213
+ NetworkToken: {
214
+ Number: payment.number,
215
+ Bin: get_last_eight_digits(payment.number),
216
+ Last4: get_last_four_digits(payment.number),
217
+ ExpMonth: (format(payment.month, :two_digits) if payment.month),
218
+ ExpYear: (format(payment.year, :two_digits) if payment.year),
219
+ Cryptogram: payment.payment_cryptogram
220
+ }
221
+ }
222
+ when CreditCard
223
+ {
224
+ type: 'card',
225
+ Card: {
226
+ Number: payment.number,
227
+ ExpMonth: (format(payment.month, :two_digits) if payment.month),
228
+ ExpYear: (format(payment.year, :two_digits) if payment.year),
229
+ Cvc: payment.verification_value
230
+ }
231
+ }
201
232
  end
202
233
  end
203
234
 
235
+ def get_last_eight_digits(number)
236
+ number[-8..-1]
237
+ end
238
+
239
+ def get_last_four_digits(number)
240
+ number[-4..-1]
241
+ end
242
+
204
243
  def add_card_holder(card, payment, options)
205
244
  requires!(options, :email)
206
245
 
@@ -178,11 +178,15 @@ module ActiveMerchant
178
178
  success = SUCCESS_CODES.include?(response[:finalstatus])
179
179
  message = success ? 'Success' : message_from(response)
180
180
 
181
- Response.new(success, message, response,
181
+ Response.new(
182
+ success,
183
+ message,
184
+ response,
182
185
  test: test?,
183
186
  authorization: response[:orderid],
184
187
  avs_result: { code: response[:avs_code] },
185
- cvv_result: response[:cvvresp])
188
+ cvv_result: response[:cvvresp]
189
+ )
186
190
  end
187
191
 
188
192
  def parse(body)
@@ -55,7 +55,8 @@ module ActiveMerchant #:nodoc:
55
55
 
56
56
  add_merchant_id(params)
57
57
  add_amount(params, amount, options)
58
- add_auth_purchase_params(params, credit_card, options)
58
+ add_auth_purchase_params(params, options)
59
+ add_credit_card(params, credit_card, 'purchase', options)
59
60
 
60
61
  commit('purchase', params: params)
61
62
  end
@@ -67,7 +68,8 @@ module ActiveMerchant #:nodoc:
67
68
 
68
69
  add_merchant_id(params)
69
70
  add_amount(params, amount, options)
70
- add_auth_purchase_params(params, credit_card, options)
71
+ add_auth_purchase_params(params, options)
72
+ add_credit_card(params, credit_card, 'purchase', options)
71
73
 
72
74
  commit('purchase', params: params)
73
75
  end
@@ -100,7 +102,7 @@ module ActiveMerchant #:nodoc:
100
102
  add_merchant_id(params)
101
103
  add_amount(params, amount, options)
102
104
  params['paymentToken'] = payment_token(authorization) || options[:payment_token]
103
- params['tenderType'] = options[:tender_type].present? ? options[:tender_type] : 'Card'
105
+ add_auth_purchase_params(params, options)
104
106
 
105
107
  commit('capture', params: params)
106
108
  end
@@ -150,9 +152,8 @@ module ActiveMerchant #:nodoc:
150
152
  params['merchantId'] = @options[:merchant_id]
151
153
  end
152
154
 
153
- def add_auth_purchase_params(params, credit_card, options)
155
+ def add_auth_purchase_params(params, options)
154
156
  add_replay_id(params, options)
155
- add_credit_card(params, credit_card, 'purchase', options)
156
157
  add_purchases_data(params, options)
157
158
  add_shipping_data(params, options)
158
159
  add_pos_data(params, options)
@@ -102,11 +102,15 @@ module ActiveMerchant #:nodoc:
102
102
  def commit(money, creditcard, options = {})
103
103
  response = parse(ssl_post(url, post_data(money, creditcard, options)))
104
104
 
105
- Response.new(successful?(response), message_from(response), response,
105
+ Response.new(
106
+ successful?(response),
107
+ message_from(response),
108
+ response,
106
109
  test: test?,
107
110
  authorization: build_authorization(response),
108
111
  avs_result: { code: response[:avsresult] },
109
- cvv_result: response[:cardidresult])
112
+ cvv_result: response[:cardidresult]
113
+ )
110
114
  end
111
115
 
112
116
  def url
@@ -259,11 +259,15 @@ module ActiveMerchant
259
259
  def commit(request)
260
260
  response = parse(ssl_post(self.live_url, post_data(request)))
261
261
 
262
- Response.new(response[:ResponseCode] == APPROVED, response[:Message], response,
262
+ Response.new(
263
+ response[:ResponseCode] == APPROVED,
264
+ response[:Message],
265
+ response,
263
266
  test: test?,
264
267
  authorization: response[:CrossReference],
265
268
  cvv_result: CVV_CODE[response[:AVSCV2Check]],
266
- avs_result: { code: AVS_CODE[response[:AVSCV2Check]] })
269
+ avs_result: { code: AVS_CODE[response[:AVSCV2Check]] }
270
+ )
267
271
  end
268
272
 
269
273
  # Put the passed data into a format that can be submitted to PSL
@@ -142,12 +142,16 @@ module ActiveMerchant #:nodoc:
142
142
  response = parse(type, data)
143
143
  message = (response[:status_message] || '').strip
144
144
 
145
- Response.new(success?(response), message, response,
145
+ Response.new(
146
+ success?(response),
147
+ message,
148
+ response,
146
149
  test: test?,
147
150
  authorization: response[:credit_card_trans_id],
148
151
  fraud_review: fraud_review?(response),
149
152
  avs_result: { code: avs_result(response) },
150
- cvv_result: cvv_result(response))
153
+ cvv_result: cvv_result(response)
154
+ )
151
155
  end
152
156
 
153
157
  def success?(response)
@@ -215,11 +215,15 @@ module ActiveMerchant #:nodoc:
215
215
  authorization = success ? authorization_for(response) : nil
216
216
  end
217
217
 
218
- Response.new(success, message, response,
218
+ Response.new(
219
+ success,
220
+ message,
221
+ response,
219
222
  test: test?,
220
223
  authorization: authorization,
221
224
  avs_result: { code: response[:AVSResponseCode] },
222
- cvv_result: response[:CVV2ResponseCode])
225
+ cvv_result: response[:CVV2ResponseCode]
226
+ )
223
227
  end
224
228
 
225
229
  # Parse the SOAP response
@@ -42,10 +42,10 @@ module ActiveMerchant #:nodoc:
42
42
  'PMT-5001' => STANDARD_ERROR_CODE[:card_declined], # Merchant does not support given payment method
43
43
 
44
44
  # System Error
45
- 'PMT-6000' => STANDARD_ERROR_CODE[:processing_error], # A temporary Issue prevented this request from being processed.
45
+ 'PMT-6000' => STANDARD_ERROR_CODE[:processing_error] # A temporary Issue prevented this request from being processed.
46
46
  }
47
47
 
48
- FRAUD_WARNING_CODES = ['PMT-1000', 'PMT-1001', 'PMT-1002', 'PMT-1003']
48
+ FRAUD_WARNING_CODES = %w(PMT-1000 PMT-1001 PMT-1002 PMT-1003)
49
49
 
50
50
  def initialize(options = {})
51
51
  # Quickbooks is deprecating OAuth 1.0 on December 17, 2019.
@@ -128,8 +128,8 @@ module ActiveMerchant #:nodoc:
128
128
  gsub(%r((oauth_nonce=\")\w+), '\1[FILTERED]').
129
129
  gsub(%r((oauth_signature=\")[a-zA-Z%0-9]+), '\1[FILTERED]').
130
130
  gsub(%r((oauth_token=\")\w+), '\1[FILTERED]').
131
- gsub(%r((number\D+)\d{16}), '\1[FILTERED]').
132
- gsub(%r((cvc\D+)\d{3}), '\1[FILTERED]').
131
+ gsub(%r((number\\\":\\\")\d+), '\1[FILTERED]').
132
+ gsub(%r((cvc\\\":\\\")\d+), '\1[FILTERED]').
133
133
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
134
134
  gsub(%r((access_token\\?":\\?")[\w\-\.]+)i, '\1[FILTERED]').
135
135
  gsub(%r((refresh_token\\?":\\?")\w+), '\1[FILTERED]').
@@ -263,7 +263,7 @@ module ActiveMerchant #:nodoc:
263
263
  oauth_parameters[:oauth_signature] = CGI.escape(Base64.encode64(hmac_signature).chomp.delete("\n"))
264
264
 
265
265
  # prepare Authorization header string
266
- oauth_parameters = Hash[oauth_parameters.sort_by { |k, _| k }]
266
+ oauth_parameters = oauth_parameters.sort_by { |k, _| k }.to_h
267
267
  oauth_headers = ["OAuth realm=\"#{@options[:realm]}\""]
268
268
  oauth_headers += oauth_parameters.map { |k, v| "#{k}=\"#{v}\"" }
269
269
 
@@ -358,6 +358,7 @@ module ActiveMerchant #:nodoc:
358
358
  rescue JSON::ParserError
359
359
  raise response_error
360
360
  end
361
+
361
362
  response_error.response.body
362
363
  end
363
364
 
@@ -153,9 +153,13 @@ module ActiveMerchant
153
153
  response = json_error(response)
154
154
  end
155
155
 
156
- Response.new(success, message_from(success, response), response,
156
+ Response.new(
157
+ success,
158
+ message_from(success, response),
159
+ response,
157
160
  test: test?,
158
- authorization: authorization_from(response))
161
+ authorization: authorization_from(response)
162
+ )
159
163
  end
160
164
 
161
165
  def authorization_from(response)
@@ -251,7 +255,7 @@ module ActiveMerchant
251
255
 
252
256
  requires!(address, :name, :address1, :city, :zip, :country)
253
257
  country = Country.find(address[:country])
254
- mapped = {
258
+ {
255
259
  name: address[:name],
256
260
  street: address[:address1],
257
261
  city: address[:city],
@@ -259,7 +263,6 @@ module ActiveMerchant
259
263
  zip_code: address[:zip],
260
264
  country_code: country.code(:alpha3).value
261
265
  }
262
- mapped
263
266
  end
264
267
 
265
268
  def format_order_id(order_id)
@@ -164,9 +164,13 @@ module ActiveMerchant #:nodoc:
164
164
  def commit(action, params)
165
165
  response = parse(ssl_post(self.live_url, post_data(action, params)))
166
166
 
167
- Response.new(successful?(response), message_from(response), response,
167
+ Response.new(
168
+ successful?(response),
169
+ message_from(response),
170
+ response,
168
171
  test: test?,
169
- authorization: response[:transaction])
172
+ authorization: response[:transaction]
173
+ )
170
174
  end
171
175
 
172
176
  def successful?(response)
@@ -1,12 +1,17 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class RapydGateway < Gateway
4
+ class_attribute :payment_redirect_test, :payment_redirect_live
5
+
4
6
  self.test_url = 'https://sandboxapi.rapyd.net/v1/'
5
7
  self.live_url = 'https://api.rapyd.net/v1/'
6
8
 
9
+ self.payment_redirect_test = 'https://sandboxpayment-redirect.rapyd.net/v1/'
10
+ self.payment_redirect_live = 'https://payment-redirect.rapyd.net/v1/'
11
+
7
12
  self.supported_countries = %w(CA CL CO DO SV PE PT VI AU HK IN ID JP MY NZ PH SG KR TW TH VN AD AT BE BA BG HR CY CZ DK EE FI FR GE DE GI GR GL HU IS IE IL IT LV LI LT LU MK MT MD MC ME NL GB NO PL RO RU SM SK SI ZA ES SE CH TR VA)
8
13
  self.default_currency = 'USD'
9
- self.supported_cardtypes = %i[visa master american_express discover]
14
+ self.supported_cardtypes = %i[visa master american_express discover verve]
10
15
 
11
16
  self.homepage_url = 'https://www.rapyd.net/'
12
17
  self.display_name = 'Rapyd Gateway'
@@ -63,11 +68,11 @@ module ActiveMerchant #:nodoc:
63
68
  def store(payment, options = {})
64
69
  post = {}
65
70
  add_payment(post, payment, options)
66
- add_customer_object(post, payment, options)
71
+ add_customer_data(post, payment, options, 'store')
67
72
  add_metadata(post, options)
68
73
  add_ewallet(post, options)
69
74
  add_payment_fields(post, options)
70
- add_payment_urls(post, options)
75
+ add_payment_urls(post, options, 'store')
71
76
  add_address(post, payment, options)
72
77
  commit(:post, 'customers', post)
73
78
  end
@@ -100,14 +105,18 @@ module ActiveMerchant #:nodoc:
100
105
  def add_auth_purchase(post, money, payment, options)
101
106
  add_invoice(post, money, options)
102
107
  add_payment(post, payment, options)
103
- add_customer_object(post, payment, options)
108
+ add_customer_data(post, payment, options)
104
109
  add_3ds(post, payment, options)
105
110
  add_address(post, payment, options)
106
111
  add_metadata(post, options)
107
112
  add_ewallet(post, options)
108
113
  add_payment_fields(post, options)
109
114
  add_payment_urls(post, options)
110
- add_customer_id(post, options)
115
+ add_idempotency(options)
116
+ end
117
+
118
+ def add_idempotency(options)
119
+ @options[:idempotency] = options[:idempotency_key] if options[:idempotency_key]
111
120
  end
112
121
 
113
122
  def add_address(post, creditcard, options)
@@ -128,6 +137,10 @@ module ActiveMerchant #:nodoc:
128
137
  def add_invoice(post, money, options)
129
138
  post[:amount] = money.zero? ? 0 : amount(money).to_f.to_s
130
139
  post[:currency] = (options[:currency] || currency(money))
140
+ post[:merchant_reference_id] = options[:merchant_reference_id] || options[:order_id]
141
+ post[:requested_currency] = options[:requested_currency] if options[:requested_currency].present?
142
+ post[:fixed_side] = options[:fixed_side] if options[:fixed_side].present?
143
+ post[:expiration] = (options[:expiration_days] || 7).to_i.days.from_now.to_i if options[:fixed_side].present?
131
144
  end
132
145
 
133
146
  def add_payment(post, payment, options)
@@ -136,15 +149,27 @@ module ActiveMerchant #:nodoc:
136
149
  elsif payment.is_a?(Check)
137
150
  add_ach(post, payment, options)
138
151
  else
139
- add_token(post, payment, options)
152
+ add_tokens(post, payment, options)
140
153
  end
141
154
  end
142
155
 
143
156
  def add_stored_credential(post, options)
144
- return unless stored_credential = options[:stored_credential]
157
+ add_network_reference_id(post, options)
158
+ add_initiation_type(post, options)
159
+ end
160
+
161
+ def add_network_reference_id(post, options)
162
+ return unless (options[:stored_credential] && options[:stored_credential][:reason_type] == 'recurring') || options[:network_transaction_id]
163
+
164
+ network_transaction_id = options[:network_transaction_id] || options[:stored_credential][:network_transaction_id]
165
+ post[:payment_method][:fields][:network_reference_id] = network_transaction_id unless network_transaction_id&.empty?
166
+ end
167
+
168
+ def add_initiation_type(post, options)
169
+ return unless options[:stored_credential] || options[:initiation_type]
145
170
 
146
- post[:payment_method][:fields][:network_reference_id] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
147
- post[:initiation_type] = stored_credential[:reason_type] if stored_credential[:reason_type]
171
+ initiation_type = options[:initiation_type] || options[:stored_credential][:reason_type]
172
+ post[:initiation_type] = initiation_type if initiation_type
148
173
  end
149
174
 
150
175
  def add_creditcard(post, payment, options)
@@ -154,14 +179,23 @@ module ActiveMerchant #:nodoc:
154
179
 
155
180
  post[:payment_method][:type] = options[:pm_type]
156
181
  pm_fields[:number] = payment.number
157
- pm_fields[:expiration_month] = payment.month.to_s
158
- pm_fields[:expiration_year] = payment.year.to_s
182
+ pm_fields[:expiration_month] = format(payment.month, :two_digits).to_s
183
+ pm_fields[:expiration_year] = format(payment.year, :two_digits).to_s
159
184
  pm_fields[:name] = "#{payment.first_name} #{payment.last_name}"
160
- pm_fields[:cvv] = payment.verification_value.to_s
161
-
185
+ pm_fields[:cvv] = payment.verification_value.to_s unless valid_network_transaction_id?(options) || payment.verification_value.blank?
186
+ pm_fields[:recurrence_type] = options[:recurrence_type] if options[:recurrence_type]
162
187
  add_stored_credential(post, options)
163
188
  end
164
189
 
190
+ def send_customer_object?(options)
191
+ options[:stored_credential] && options[:stored_credential][:reason_type] == 'recurring'
192
+ end
193
+
194
+ def valid_network_transaction_id?(options)
195
+ network_transaction_id = options[:network_tansaction_id] || options.dig(:stored_credential_options, :network_transaction_id) || options.dig(:stored_credential, :network_transaction_id)
196
+ return network_transaction_id.present?
197
+ end
198
+
165
199
  def add_ach(post, payment, options)
166
200
  post[:payment_method] = {}
167
201
  post[:payment_method][:fields] = {}
@@ -175,22 +209,27 @@ module ActiveMerchant #:nodoc:
175
209
  post[:payment_method][:fields][:payment_purpose] = options[:payment_purpose] if options[:payment_purpose]
176
210
  end
177
211
 
178
- def add_token(post, payment, options)
179
- return unless token = payment.split('|')[1]
212
+ def add_tokens(post, payment, options)
213
+ return unless payment.respond_to?(:split)
180
214
 
181
- post[:payment_method] = token
215
+ customer_id, card_id = payment.split('|')
216
+
217
+ post[:customer] = customer_id unless send_customer_object?(options)
218
+ post[:payment_method] = card_id
182
219
  end
183
220
 
184
221
  def add_3ds(post, payment, options)
185
- return unless three_d_secure = options[:three_d_secure]
186
-
187
- post[:payment_method_options] = {}
188
- post[:payment_method_options]['3d_required'] = three_d_secure[:required]
189
- post[:payment_method_options]['3d_version'] = three_d_secure[:version]
190
- post[:payment_method_options][:cavv] = three_d_secure[:cavv]
191
- post[:payment_method_options][:eci] = three_d_secure[:eci]
192
- post[:payment_method_options][:xid] = three_d_secure[:xid]
193
- post[:payment_method_options][:ds_trans_id] = three_d_secure[:ds_transaction_id]
222
+ if options[:execute_threed] == true
223
+ post[:payment_method_options] = { '3d_required' => true } if options[:force_3d_secure].to_s == 'true'
224
+ elsif three_d_secure = options[:three_d_secure]
225
+ post[:payment_method_options] = {}
226
+ post[:payment_method_options]['3d_required'] = three_d_secure[:required]
227
+ post[:payment_method_options]['3d_version'] = three_d_secure[:version]
228
+ post[:payment_method_options][:cavv] = three_d_secure[:cavv]
229
+ post[:payment_method_options][:eci] = three_d_secure[:eci]
230
+ post[:payment_method_options][:xid] = three_d_secure[:xid]
231
+ post[:payment_method_options][:ds_trans_id] = three_d_secure[:ds_transaction_id]
232
+ end
194
233
  end
195
234
 
196
235
  def add_metadata(post, options)
@@ -198,27 +237,67 @@ module ActiveMerchant #:nodoc:
198
237
  end
199
238
 
200
239
  def add_ewallet(post, options)
201
- post[:ewallet_id] = options[:ewallet_id] if options[:ewallet_id]
240
+ post[:ewallet] = options[:ewallet_id] if options[:ewallet_id]
202
241
  end
203
242
 
204
243
  def add_payment_fields(post, options)
205
- post[:payment] = {}
244
+ post[:description] = options[:description] if options[:description]
245
+ post[:statement_descriptor] = options[:statement_descriptor] if options[:statement_descriptor]
246
+ post[:save_payment_method] = options[:save_payment_method] if options[:save_payment_method]
247
+ end
248
+
249
+ def add_payment_urls(post, options, action = '')
250
+ if action == 'store'
251
+ url_location = post[:payment_method]
252
+ else
253
+ url_location = post
254
+ end
255
+
256
+ url_location[:complete_payment_url] = options[:complete_payment_url] if options[:complete_payment_url]
257
+ url_location[:error_payment_url] = options[:error_payment_url] if options[:error_payment_url]
258
+ end
259
+
260
+ def add_customer_data(post, payment, options, action = '')
261
+ phone_number = options.dig(:billing_address, :phone) || options.dig(:billing_address, :phone_number)
262
+ post[:phone_number] = phone_number.gsub(/\D/, '') unless phone_number.nil?
263
+ post[:receipt_email] = options[:email] if payment.is_a?(String) && options[:customer_id].present? && !send_customer_object?(options)
206
264
 
207
- post[:payment][:description] = options[:description] if options[:description]
208
- post[:payment][:statement_descriptor] = options[:statement_descriptor] if options[:statement_descriptor]
265
+ return if payment.is_a?(String)
266
+ return add_customer_id(post, options) if options[:customer_id]
267
+
268
+ if action == 'store'
269
+ post.merge!(customer_fields(payment, options))
270
+ else
271
+ post[:customer] = customer_fields(payment, options) unless send_customer_object?(options)
272
+ end
209
273
  end
210
274
 
211
- def add_payment_urls(post, options)
212
- post[:complete_payment_url] = options[:complete_payment_url] if options[:complete_payment_url]
213
- post[:error_payment_url] = options[:error_payment_url] if options[:error_payment_url]
275
+ def customer_fields(payment, options)
276
+ return if options[:customer_id]
277
+
278
+ customer_address = address(options)
279
+ customer_data = {}
280
+ customer_data[:name] = "#{payment.first_name} #{payment.last_name}" unless payment.is_a?(String)
281
+ customer_data[:email] = options[:email] unless payment.is_a?(String) && options[:customer_id].blank?
282
+ customer_data[:addresses] = [customer_address] if customer_address
283
+ customer_data
214
284
  end
215
285
 
216
- def add_customer_object(post, payment, options)
217
- post[:name] = "#{payment.first_name} #{payment.last_name}" unless payment.is_a?(String)
218
- phone = options.dig(:billing_address, :phone) .gsub(/\D/, '') unless options[:billing_address].nil?
219
- post[:phone_number] = phone || options.dig(:customer, :phone_number)
220
- post[:email] = options[:email] || options.dig(:customer, :email)
221
- post[:addresses] = options.dig(:customer, :addresses) if USA_PAYMENT_METHODS.include?(options[:pm_type])
286
+ def address(options)
287
+ return unless address = options[:billing_address]
288
+
289
+ formatted_address = {}
290
+
291
+ formatted_address[:name] = address[:name] if address[:name]
292
+ formatted_address[:line_1] = address[:address1] if address[:address1]
293
+ formatted_address[:line_2] = address[:address2] if address[:address2]
294
+ formatted_address[:city] = address[:city] if address[:city]
295
+ formatted_address[:state] = address[:state] if address[:state]
296
+ formatted_address[:country] = address[:country] if address[:country]
297
+ formatted_address[:zip] = address[:zip] if address[:zip]
298
+ formatted_address[:phone_number] = address[:phone].gsub(/\D/, '') if address[:phone]
299
+
300
+ formatted_address
222
301
  end
223
302
 
224
303
  def add_customer_id(post, options)
@@ -228,13 +307,21 @@ module ActiveMerchant #:nodoc:
228
307
  def parse(body)
229
308
  return {} if body.empty? || body.nil?
230
309
 
231
- JSON.parse(body)
310
+ parsed = JSON.parse(body)
311
+ parsed.is_a?(Hash) ? parsed : { 'status' => { 'status' => parsed } }
312
+ end
313
+
314
+ def url(action, url_override = nil)
315
+ if url_override.to_s == 'payment_redirect' && action == 'payments'
316
+ (self.test? ? self.payment_redirect_test : self.payment_redirect_live) + action.to_s
317
+ else
318
+ (self.test? ? self.test_url : self.live_url) + action.to_s
319
+ end
232
320
  end
233
321
 
234
322
  def commit(method, action, parameters)
235
- url = (test? ? test_url : live_url) + action.to_s
236
323
  rel_path = "#{method}/v1/#{action}"
237
- response = api_request(method, url, rel_path, parameters)
324
+ response = api_request(method, url(action, @options[:url_override]), rel_path, parameters)
238
325
 
239
326
  Response.new(
240
327
  success_from(response),
@@ -246,10 +333,25 @@ module ActiveMerchant #:nodoc:
246
333
  test: test?,
247
334
  error_code: error_code_from(response)
248
335
  )
336
+ rescue ActiveMerchant::ResponseError => e
337
+ response = e.response.body.present? ? parse(e.response.body) : { 'status' => { 'response_code' => e.response.msg } }
338
+ message = response['status'].slice('message', 'response_code').values.select(&:present?).first || ''
339
+ Response.new(false, message, response, test: test?, error_code: error_code_from(response))
340
+ end
341
+
342
+ # We need to revert the work of ActiveSupport JSON encoder to prevent discrepancies
343
+ # Between the signature and the actual request body
344
+ def revert_json_html_encoding!(string)
345
+ {
346
+ '\\u003e' => '>',
347
+ '\\u003c' => '<',
348
+ '\\u0026' => '&'
349
+ }.each { |k, v| string.gsub! k, v }
249
350
  end
250
351
 
251
352
  def api_request(method, url, rel_path, params)
252
353
  params == {} ? body = '' : body = params.to_json
354
+ revert_json_html_encoding!(body) if defined?(ActiveSupport::JSON::Encoding) && ActiveSupport::JSON::Encoding.escape_html_entities_in_json
253
355
  parse(ssl_request(method, url, body, headers(rel_path, body)))
254
356
  end
255
357
 
@@ -261,14 +363,14 @@ module ActiveMerchant #:nodoc:
261
363
  'access_key' => @options[:access_key],
262
364
  'salt' => salt,
263
365
  'timestamp' => timestamp,
264
- 'signature' => generate_hmac(rel_path, salt, timestamp, payload)
265
- }
366
+ 'signature' => generate_hmac(rel_path, salt, timestamp, payload),
367
+ 'idempotency' => @options[:idempotency]
368
+ }.delete_if { |_, value| value.nil? }
266
369
  end
267
370
 
268
371
  def generate_hmac(rel_path, salt, timestamp, payload)
269
372
  signature = "#{rel_path}#{salt}#{timestamp}#{@options[:access_key]}#{@options[:secret_key]}#{payload}"
270
- hash = Base64.urlsafe_encode64(OpenSSL::HMAC.hexdigest('sha256', @options[:secret_key], signature))
271
- hash
373
+ Base64.urlsafe_encode64(OpenSSL::HMAC.hexdigest('sha256', @options[:secret_key], signature))
272
374
  end
273
375
 
274
376
  def avs_result(response)
@@ -303,7 +405,7 @@ module ActiveMerchant #:nodoc:
303
405
  end
304
406
 
305
407
  def error_code_from(response)
306
- response.dig('status', 'error_code') unless success_from(response)
408
+ response.dig('status', 'error_code') || response.dig('status', 'response_code') || ''
307
409
  end
308
410
 
309
411
  def handle_response(response)