activemerchant 1.133.0 → 1.137.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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)