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
@@ -4,7 +4,14 @@ module ActiveMerchant #:nodoc:
4
4
  self.test_url = 'https://checkout.rch.how/'
5
5
  self.live_url = 'https://checkout.rch.io/'
6
6
 
7
- self.supported_countries = ['US']
7
+ self.supported_countries = %w(AE AG AL AM AT AU AW AZ BA BB BD BE BF BG BH BJ BM BN BO BR BS BW BZ CA CD CF
8
+ CH CI CL CM CN CO CR CU CV CY CZ DE DJ DK DM DO DZ EE EG ES ET FI FJ FK FR GA
9
+ GB GD GE GG GH GI GN GR GT GU GW GY HK HN HR HU ID IE IL IM IN IS IT JE JM JO
10
+ JP KE KG KH KM KN KR KW KY KZ LA LC LK LR LT LU LV LY MA MD MK ML MN MO MR MS
11
+ MT MU MV MW MX MY MZ NA NC NE NG NI NL NO NP NZ OM PA PE PF PG PH PK PL PT PY
12
+ QA RO RS RW SA SB SC SE SG SH SI SK SL SN SO SR ST SV SY SZ TD TG TH TN TO TR
13
+ TT TV TW TZ UG US UY UZ VC VN VU WF WS YE ZM)
14
+
8
15
  self.default_currency = 'USD'
9
16
  self.supported_cardtypes = %i[visa diners_club american_express jcb master discover maestro]
10
17
 
@@ -71,10 +78,10 @@ module ActiveMerchant #:nodoc:
71
78
 
72
79
  def scrub(transcript)
73
80
  transcript.
74
- gsub(%r(((MerchantId)[% \w]+[%]\d{2})[\w -]+), '\1[FILTERED]').
81
+ gsub(%r(((MerchantId)[% \w]+%\d{2})[\w -]+), '\1[FILTERED]').
75
82
  gsub(%r((signature=)[\w%]+), '\1[FILTERED]\2').
76
- gsub(%r((Number%22%3A%22)[\d]+), '\1[FILTERED]\2').
77
- gsub(%r((VerificationCode%22%3A)[\d]+), '\1[FILTERED]\2')
83
+ gsub(%r((Number%22%3A%22)\d+), '\1[FILTERED]\2').
84
+ gsub(%r((VerificationCode%22%3A)\d+), '\1[FILTERED]\2')
78
85
  end
79
86
 
80
87
  def refund(amount, authorization, options = {})
@@ -266,14 +266,7 @@ module ActiveMerchant #:nodoc:
266
266
  end
267
267
 
268
268
  def verify(creditcard, options = {})
269
- if options[:sca_exemption_behavior_override] == 'endpoint_and_ntid'
270
- purchase(0, creditcard, options)
271
- else
272
- MultiResponse.run(:use_first_response) do |r|
273
- r.process { authorize(100, creditcard, options) }
274
- r.process(:ignore_result) { void(r.authorization, options) }
275
- end
276
- end
269
+ purchase(0, creditcard, options)
277
270
  end
278
271
 
279
272
  def supports_scrubbing
@@ -696,8 +689,7 @@ module ActiveMerchant #:nodoc:
696
689
 
697
690
  order_id += "\0" until order_id.bytesize % block_length == 0 # Pad with zeros
698
691
 
699
- output = cipher.update(order_id) + cipher.final
700
- output
692
+ cipher.update(order_id) + cipher.final
701
693
  end
702
694
 
703
695
  def mac256(key, data)
@@ -0,0 +1,507 @@
1
+ # coding: utf-8
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # = Redsys Merchant Gateway
6
+ #
7
+ # Gateway support for the Spanish "Redsys" payment gateway system. This is
8
+ # used by many banks in Spain and is particularly well supported by
9
+ # Catalunya Caixa's ecommerce department.
10
+ #
11
+ # Redsys requires an order_id be provided with each transaction and it must
12
+ # follow a specific format. The rules are as follows:
13
+ #
14
+ # * First 4 digits must be numerical
15
+ # * Remaining 8 digits may be alphanumeric
16
+ # * Max length: 12
17
+ #
18
+ # If an invalid order_id is provided, we do our best to clean it up.
19
+ #
20
+ # Written by Piers Chambers (Varyonic.com)
21
+ #
22
+ # *** SHA256 Authentication Update ***
23
+ #
24
+ # Redsys has dropped support for the SHA1 authentication method.
25
+ # Developer documentation: https://pagosonline.redsys.es/desarrolladores.html
26
+ class RedsysRestGateway < Gateway
27
+ self.test_url = 'https://sis-t.redsys.es:25443/sis/rest/'
28
+ self.live_url = 'https://sis.redsys.es/sis/rest/'
29
+
30
+ self.supported_countries = ['ES']
31
+ self.default_currency = 'EUR'
32
+ self.money_format = :cents
33
+ # Not all card types may be activated by the bank!
34
+ self.supported_cardtypes = %i[visa master american_express jcb diners_club unionpay]
35
+ self.homepage_url = 'http://www.redsys.es/'
36
+ self.display_name = 'Redsys (REST)'
37
+
38
+ CURRENCY_CODES = {
39
+ 'AED' => '784',
40
+ 'ARS' => '32',
41
+ 'AUD' => '36',
42
+ 'BRL' => '986',
43
+ 'BOB' => '68',
44
+ 'CAD' => '124',
45
+ 'CHF' => '756',
46
+ 'CLP' => '152',
47
+ 'CNY' => '156',
48
+ 'COP' => '170',
49
+ 'CRC' => '188',
50
+ 'CZK' => '203',
51
+ 'DKK' => '208',
52
+ 'DOP' => '214',
53
+ 'EUR' => '978',
54
+ 'GBP' => '826',
55
+ 'GTQ' => '320',
56
+ 'HUF' => '348',
57
+ 'IDR' => '360',
58
+ 'INR' => '356',
59
+ 'JPY' => '392',
60
+ 'KRW' => '410',
61
+ 'MYR' => '458',
62
+ 'MXN' => '484',
63
+ 'NOK' => '578',
64
+ 'NZD' => '554',
65
+ 'PEN' => '604',
66
+ 'PLN' => '985',
67
+ 'RUB' => '643',
68
+ 'SAR' => '682',
69
+ 'SEK' => '752',
70
+ 'SGD' => '702',
71
+ 'THB' => '764',
72
+ 'TWD' => '901',
73
+ 'USD' => '840',
74
+ 'UYU' => '858'
75
+ }
76
+
77
+ THREEDS_EXEMPTIONS = {
78
+ corporate_card: 'COR',
79
+ delegated_authentication: 'ATD',
80
+ low_risk: 'TRA',
81
+ low_value: 'LWV',
82
+ stored_credential: 'MIT',
83
+ trusted_merchant: 'NDF'
84
+ }
85
+
86
+ # The set of supported transactions for this gateway.
87
+ # More operations are supported by the gateway itself, but
88
+ # are not supported in this library.
89
+ SUPPORTED_TRANSACTIONS = {
90
+ purchase: '0',
91
+ authorize: '1',
92
+ capture: '2',
93
+ refund: '3',
94
+ cancel: '9',
95
+ verify: '7'
96
+ }
97
+
98
+ # These are the text meanings sent back by the acquirer when
99
+ # a card has been rejected. Syntax or general request errors
100
+ # are not covered here.
101
+ RESPONSE_TEXTS = {
102
+ 0 => 'Transaction Approved',
103
+ 400 => 'Cancellation Accepted',
104
+ 481 => 'Cancellation Accepted',
105
+ 500 => 'Reconciliation Accepted',
106
+ 900 => 'Refund / Confirmation approved',
107
+
108
+ 101 => 'Card expired',
109
+ 102 => 'Card blocked temporarily or under susciption of fraud',
110
+ 104 => 'Transaction not permitted',
111
+ 107 => 'Contact the card issuer',
112
+ 109 => 'Invalid identification by merchant or POS terminal',
113
+ 110 => 'Invalid amount',
114
+ 114 => 'Card cannot be used to the requested transaction',
115
+ 116 => 'Insufficient credit',
116
+ 118 => 'Non-registered card',
117
+ 125 => 'Card not effective',
118
+ 129 => 'CVV2/CVC2 Error',
119
+ 167 => 'Contact the card issuer: suspected fraud',
120
+ 180 => 'Card out of service',
121
+ 181 => 'Card with credit or debit restrictions',
122
+ 182 => 'Card with credit or debit restrictions',
123
+ 184 => 'Authentication error',
124
+ 190 => 'Refusal with no specific reason',
125
+ 191 => 'Expiry date incorrect',
126
+ 195 => 'Requires SCA authentication',
127
+
128
+ 201 => 'Card expired',
129
+ 202 => 'Card blocked temporarily or under suspicion of fraud',
130
+ 204 => 'Transaction not permitted',
131
+ 207 => 'Contact the card issuer',
132
+ 208 => 'Lost or stolen card',
133
+ 209 => 'Lost or stolen card',
134
+ 280 => 'CVV2/CVC2 Error',
135
+ 290 => 'Declined with no specific reason',
136
+
137
+ 480 => 'Original transaction not located, or time-out exceeded',
138
+ 501 => 'Original transaction not located, or time-out exceeded',
139
+ 502 => 'Original transaction not located, or time-out exceeded',
140
+ 503 => 'Original transaction not located, or time-out exceeded',
141
+
142
+ 904 => 'Merchant not registered at FUC',
143
+ 909 => 'System error',
144
+ 912 => 'Issuer not available',
145
+ 913 => 'Duplicate transmission',
146
+ 916 => 'Amount too low',
147
+ 928 => 'Time-out exceeded',
148
+ 940 => 'Transaction cancelled previously',
149
+ 941 => 'Authorization operation already cancelled',
150
+ 942 => 'Original authorization declined',
151
+ 943 => 'Different details from origin transaction',
152
+ 944 => 'Session error',
153
+ 945 => 'Duplicate transmission',
154
+ 946 => 'Cancellation of transaction while in progress',
155
+ 947 => 'Duplicate tranmission while in progress',
156
+ 949 => 'POS Inoperative',
157
+ 950 => 'Refund not possible',
158
+ 9064 => 'Card number incorrect',
159
+ 9078 => 'No payment method available',
160
+ 9093 => 'Non-existent card',
161
+ 9218 => 'Recursive transaction in bad gateway',
162
+ 9253 => 'Check-digit incorrect',
163
+ 9256 => 'Preauth not allowed for merchant',
164
+ 9257 => 'Preauth not allowed for card',
165
+ 9261 => 'Operating limit exceeded',
166
+ 9912 => 'Issuer not available',
167
+ 9913 => 'Confirmation error',
168
+ 9914 => 'KO Confirmation'
169
+ }
170
+
171
+ # Expected values as per documentation
172
+ THREE_DS_V2 = '2.1.0'
173
+
174
+ # Creates a new instance
175
+ #
176
+ # Redsys requires a login and secret_key, and optionally also accepts a
177
+ # non-default terminal.
178
+ #
179
+ # ==== Options
180
+ #
181
+ # * <tt>:login</tt> -- The Redsys Merchant ID (REQUIRED)
182
+ # * <tt>:secret_key</tt> -- The Redsys Secret Key. (REQUIRED)
183
+ # * <tt>:terminal</tt> -- The Redsys Terminal. Defaults to 1. (OPTIONAL)
184
+ # * <tt>:test</tt> -- +true+ or +false+. Defaults to +false+. (OPTIONAL)
185
+ def initialize(options = {})
186
+ requires!(options, :login, :secret_key)
187
+ options[:terminal] ||= 1
188
+ options[:signature_algorithm] = 'sha256'
189
+ super
190
+ end
191
+
192
+ def purchase(money, payment, options = {})
193
+ requires!(options, :order_id)
194
+
195
+ post = {}
196
+ add_action(post, :purchase, options)
197
+ add_amount(post, money, options)
198
+ add_stored_credentials(post, options)
199
+ add_threeds_exemption_data(post, options)
200
+ add_order(post, options[:order_id])
201
+ add_payment(post, payment)
202
+ add_description(post, options)
203
+ add_direct_payment(post, options)
204
+ add_threeds(post, options)
205
+
206
+ commit(post, options)
207
+ end
208
+
209
+ def authorize(money, payment, options = {})
210
+ requires!(options, :order_id)
211
+
212
+ post = {}
213
+ add_action(post, :authorize, options)
214
+ add_amount(post, money, options)
215
+ add_stored_credentials(post, options)
216
+ add_threeds_exemption_data(post, options)
217
+ add_order(post, options[:order_id])
218
+ add_payment(post, payment)
219
+ add_description(post, options)
220
+ add_direct_payment(post, options)
221
+ add_threeds(post, options)
222
+
223
+ commit(post, options)
224
+ end
225
+
226
+ def capture(money, authorization, options = {})
227
+ post = {}
228
+ add_action(post, :capture)
229
+ add_amount(post, money, options)
230
+ order_id, = split_authorization(authorization)
231
+ add_order(post, order_id)
232
+ add_description(post, options)
233
+
234
+ commit(post, options)
235
+ end
236
+
237
+ def void(authorization, options = {})
238
+ requires!(options, :order_id)
239
+
240
+ post = {}
241
+ add_action(post, :cancel)
242
+ order_id, amount, currency = split_authorization(authorization)
243
+ add_amount(post, amount, currency: currency)
244
+ add_order(post, order_id)
245
+ add_description(post, options)
246
+
247
+ commit(post, options)
248
+ end
249
+
250
+ def refund(money, authorization, options = {})
251
+ requires!(options, :order_id)
252
+
253
+ post = {}
254
+ add_action(post, :refund)
255
+ add_amount(post, money, options)
256
+ order_id, = split_authorization(authorization)
257
+ add_order(post, order_id)
258
+ add_description(post, options)
259
+
260
+ commit(post, options)
261
+ end
262
+
263
+ def verify(creditcard, options = {})
264
+ requires!(options, :order_id)
265
+
266
+ post = {}
267
+ add_action(post, :verify, options)
268
+ add_amount(post, 0, options)
269
+ add_order(post, options[:order_id])
270
+ add_payment(post, creditcard)
271
+ add_description(post, options)
272
+ add_direct_payment(post, options)
273
+ add_threeds(post, options)
274
+
275
+ commit(post, options)
276
+ end
277
+
278
+ def supports_scrubbing?
279
+ true
280
+ end
281
+
282
+ def scrub(transcript)
283
+ transcript.
284
+ gsub(%r((PAN\"=>\")(\d+)), '\1[FILTERED]').
285
+ gsub(%r((CVV2\"=>\")(\d+)), '\1[FILTERED]')
286
+ end
287
+
288
+ private
289
+
290
+ def add_direct_payment(post, options)
291
+ # Direct payment skips 3DS authentication. We should only apply this if execute_threed is false
292
+ # or authentication data is not present. Authentication data support to be added in the future.
293
+ return if options[:execute_threed] || options[:authentication_data] || options[:three_ds_exemption_type] == 'moto'
294
+
295
+ post[:DS_MERCHANT_DIRECTPAYMENT] = true
296
+ end
297
+
298
+ def add_threeds(post, options)
299
+ return unless options[:execute_threed] || options[:three_ds_2]
300
+
301
+ post[:DS_MERCHANT_EMV3DS] = if options[:execute_threed]
302
+ { threeDSInfo: 'CardData' }
303
+ else
304
+ add_browser_info(post, options)
305
+ end
306
+ end
307
+
308
+ def add_browser_info(post, options)
309
+ return unless browser_info = options.dig(:three_ds_2, :browser_info)
310
+
311
+ {
312
+ browserAcceptHeader: browser_info[:accept_header],
313
+ browserUserAgent: browser_info[:user_agent],
314
+ browserJavaEnabled: browser_info[:java],
315
+ browserJavascriptEnabled: browser_info[:java],
316
+ browserLanguage: browser_info[:language],
317
+ browserColorDepth: browser_info[:depth],
318
+ browserScreenHeight: browser_info[:height],
319
+ browserScreenWidth: browser_info[:width],
320
+ browserTZ: browser_info[:timezone]
321
+ }
322
+ end
323
+
324
+ def add_action(post, action, options = {})
325
+ post[:DS_MERCHANT_TRANSACTIONTYPE] = transaction_code(action)
326
+ end
327
+
328
+ def add_amount(post, money, options)
329
+ post[:DS_MERCHANT_AMOUNT] = amount(money).to_s
330
+ post[:DS_MERCHANT_CURRENCY] = currency_code(options[:currency] || currency(money))
331
+ end
332
+
333
+ def add_description(post, options)
334
+ post[:DS_MERCHANT_PRODUCTDESCRIPTION] = CGI.escape(options[:description]) if options[:description]
335
+ end
336
+
337
+ def add_order(post, order_id)
338
+ post[:DS_MERCHANT_ORDER] = clean_order_id(order_id)
339
+ end
340
+
341
+ def add_payment(post, card)
342
+ name = [card.first_name, card.last_name].join(' ').slice(0, 60)
343
+ year = sprintf('%.4i', card.year)
344
+ month = sprintf('%.2i', card.month)
345
+ post['DS_MERCHANT_TITULAR'] = CGI.escape(name)
346
+ post['DS_MERCHANT_PAN'] = card.number
347
+ post['DS_MERCHANT_EXPIRYDATE'] = "#{year[2..3]}#{month}"
348
+ post['DS_MERCHANT_CVV2'] = card.verification_value if card.verification_value.present?
349
+ end
350
+
351
+ def determine_action(options)
352
+ # If execute_threed is true, we need to use iniciaPeticionREST to set up authentication
353
+ # Otherwise we are skipping 3DS or we should have 3DS authentication results
354
+ options[:execute_threed] ? 'iniciaPeticionREST' : 'trataPeticionREST'
355
+ end
356
+
357
+ def commit(post, options)
358
+ url = (test? ? test_url : live_url)
359
+ action = determine_action(options)
360
+ raw_response = parse(ssl_post(url + action, post_data(post, options)))
361
+ payload = raw_response['Ds_MerchantParameters']
362
+ return Response.new(false, "#{raw_response['errorCode']} ERROR") unless payload
363
+
364
+ response = JSON.parse(Base64.decode64(payload)).transform_keys!(&:downcase).with_indifferent_access
365
+ return Response.new(false, 'Unable to verify response') unless validate_signature(payload, raw_response['Ds_Signature'], response[:ds_order])
366
+
367
+ succeeded = success_from(response, options)
368
+ Response.new(
369
+ succeeded,
370
+ message_from(response),
371
+ response,
372
+ authorization: authorization_from(response),
373
+ test: test?,
374
+ error_code: succeeded ? nil : response[:ds_response]
375
+ )
376
+ end
377
+
378
+ def post_data(post, options)
379
+ add_authentication(post, options)
380
+ merchant_parameters = JSON.generate(post)
381
+ encoded_parameters = Base64.strict_encode64(merchant_parameters)
382
+ post_data = PostData.new
383
+ post_data['Ds_SignatureVersion'] = 'HMAC_SHA256_V1'
384
+ post_data['Ds_MerchantParameters'] = encoded_parameters
385
+ post_data['Ds_Signature'] = sign_request(encoded_parameters, post[:DS_MERCHANT_ORDER])
386
+ post_data.to_post_data
387
+ end
388
+
389
+ def add_authentication(post, options)
390
+ post[:DS_MERCHANT_TERMINAL] = options[:terminal] || @options[:terminal]
391
+ post[:DS_MERCHANT_MERCHANTCODE] = @options[:login]
392
+ end
393
+
394
+ def add_stored_credentials(post, options)
395
+ return unless stored_credential = options[:stored_credential]
396
+
397
+ post[:DS_MERCHANT_COF_INI] = stored_credential[:initial_transaction] ? 'S' : 'N'
398
+
399
+ post[:DS_MERCHANT_COF_TYPE] = case stored_credential[:reason_type]
400
+ when 'recurring'
401
+ 'R'
402
+ when 'installment'
403
+ 'I'
404
+ else
405
+ 'C'
406
+ end
407
+
408
+ post[:DS_MERCHANT_IDENTIFIER] = 'REQUIRED' if stored_credential[:initiator] == 'cardholder'
409
+ post[:DS_MERCHANT_COF_TXNID] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
410
+ end
411
+
412
+ def add_threeds_exemption_data(post, options)
413
+ return unless options[:three_ds_exemption_type]
414
+
415
+ if options[:three_ds_exemption_type] == 'moto'
416
+ post[:DS_MERCHANT_DIRECTPAYMENT] = 'MOTO'
417
+ else
418
+ exemption = options[:three_ds_exemption_type].to_sym
419
+ post[:DS_MERCHANT_EXCEP_SCA] = THREEDS_EXEMPTIONS[exemption]
420
+ end
421
+ end
422
+
423
+ def parse(body)
424
+ JSON.parse(body)
425
+ end
426
+
427
+ def success_from(response, options)
428
+ return true if response[:ds_emv3ds] && options[:execute_threed]
429
+
430
+ # Need to get updated for 3DS support
431
+ if code = response[:ds_response]
432
+ (code.to_i < 100) || [400, 481, 500, 900].include?(code.to_i)
433
+ else
434
+ false
435
+ end
436
+ end
437
+
438
+ def message_from(response)
439
+ return response.dig(:ds_emv3ds, :threeDSInfo) if response[:ds_emv3ds]
440
+
441
+ code = response[:ds_response]&.to_i
442
+ code = 0 if code < 100
443
+ RESPONSE_TEXTS[code] || 'Unknown code, please check in manual'
444
+ end
445
+
446
+ def validate_signature(data, signature, order_number)
447
+ key = encrypt(@options[:secret_key], order_number)
448
+ Base64.urlsafe_encode64(mac256(key, data)) == signature
449
+ end
450
+
451
+ def authorization_from(response)
452
+ # Need to get updated for 3DS support
453
+ [response[:ds_order], response[:ds_amount], response[:ds_currency]].join('|')
454
+ end
455
+
456
+ def split_authorization(authorization)
457
+ order_id, amount, currency = authorization.split('|')
458
+ [order_id, amount.to_i, currency]
459
+ end
460
+
461
+ def currency_code(currency)
462
+ return currency if currency =~ /^\d+$/
463
+ raise ArgumentError, "Unknown currency #{currency}" unless CURRENCY_CODES[currency]
464
+
465
+ CURRENCY_CODES[currency]
466
+ end
467
+
468
+ def transaction_code(type)
469
+ SUPPORTED_TRANSACTIONS[type]
470
+ end
471
+
472
+ def clean_order_id(order_id)
473
+ cleansed = order_id.gsub(/[^\da-zA-Z]/, '')
474
+ if /^\d{4}/.match?(cleansed)
475
+ cleansed[0..11]
476
+ else
477
+ '%04d' % [rand(0..9999)] + cleansed[0...8]
478
+ end
479
+ end
480
+
481
+ def sign_request(encoded_parameters, order_id)
482
+ raise(ArgumentError, 'missing order_id') unless order_id
483
+
484
+ key = encrypt(@options[:secret_key], order_id)
485
+ Base64.strict_encode64(mac256(key, encoded_parameters))
486
+ end
487
+
488
+ def encrypt(key, order_id)
489
+ block_length = 8
490
+ cipher = OpenSSL::Cipher.new('DES3')
491
+ cipher.encrypt
492
+
493
+ cipher.key = Base64.urlsafe_decode64(key)
494
+ # The OpenSSL default of an all-zeroes ("\\0") IV is used.
495
+ cipher.padding = 0
496
+
497
+ order_id += "\0" until order_id.bytesize % block_length == 0 # Pad with zeros
498
+
499
+ cipher.update(order_id) + cipher.final
500
+ end
501
+
502
+ def mac256(key, data)
503
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, data)
504
+ end
505
+ end
506
+ end
507
+ end
@@ -128,9 +128,7 @@ module ActiveMerchant #:nodoc:
128
128
  end
129
129
 
130
130
  def add_account(xml, payment_method)
131
- if !payment_method.respond_to?(:number)
132
- xml.Account(registration: payment_method)
133
- else
131
+ if payment_method.respond_to?(:number)
134
132
  xml.Account do
135
133
  xml.Number payment_method.number
136
134
  xml.Holder "#{payment_method.first_name} #{payment_method.last_name}"
@@ -138,6 +136,8 @@ module ActiveMerchant #:nodoc:
138
136
  xml.Expiry(year: payment_method.year, month: payment_method.month)
139
137
  xml.Verification payment_method.verification_value
140
138
  end
139
+ else
140
+ xml.Account(registration: payment_method)
141
141
  end
142
142
  end
143
143
 
@@ -88,7 +88,7 @@ module ActiveMerchant #:nodoc:
88
88
  add_transaction_data('Credit', post, money, options)
89
89
  add_customer_details(post, payment, options)
90
90
 
91
- post[:sg_CreditType] = 1
91
+ options[:unreferenced_refund].to_s == 'true' ? post[:sg_CreditType] = 2 : post[:sg_CreditType] = 1
92
92
 
93
93
  commit(post)
94
94
  end
@@ -149,26 +149,46 @@ module ActiveMerchant #:nodoc:
149
149
  end
150
150
 
151
151
  def add_payment(post, payment, options = {})
152
- post[:sg_ExpMonth] = format(payment.month, :two_digits)
153
- post[:sg_ExpYear] = format(payment.year, :two_digits)
154
- post[:sg_CardNumber] = payment.number
155
-
156
- if payment.is_a?(NetworkTokenizationCreditCard) && payment.source == :network_token
157
- post[:sg_CAVV] = payment.payment_cryptogram
158
- post[:sg_ECI] = options[:three_d_secure] && options[:three_d_secure][:eci] || '05'
159
- post[:sg_IsExternalMPI] = 1
160
- post[:sg_ExternalTokenProvider] = 5
161
- else
162
- post[:sg_CVV2] = payment.verification_value
163
- post[:sg_NameOnCard] = payment.name
164
- post[:sg_StoredCredentialMode] = (options[:stored_credential_mode] == true ? 1 : 0)
152
+ case payment
153
+ when String
154
+ add_token(post, payment)
155
+ when CreditCard
156
+ post[:sg_ExpMonth] = format(payment.month, :two_digits)
157
+ post[:sg_ExpYear] = format(payment.year, :two_digits)
158
+ post[:sg_CardNumber] = payment.number
159
+
160
+ if payment.is_a?(NetworkTokenizationCreditCard) && payment.source == :network_token
161
+ add_network_token(post, payment, options)
162
+ else
163
+ add_credit_card(post, payment, options)
164
+ end
165
165
  end
166
166
  end
167
167
 
168
+ def add_token(post, payment)
169
+ _, transaction_id, token = payment.split('|')
170
+
171
+ post[:sg_TransactionID] = transaction_id
172
+ post[:sg_CCToken] = token
173
+ end
174
+
175
+ def add_credit_card(post, payment, options)
176
+ post[:sg_CVV2] = payment.verification_value
177
+ post[:sg_NameOnCard] = payment.name
178
+ post[:sg_StoredCredentialMode] = (options[:stored_credential_mode] == true ? 1 : 0)
179
+ end
180
+
181
+ def add_network_token(post, payment, options)
182
+ post[:sg_CAVV] = payment.payment_cryptogram
183
+ post[:sg_ECI] = options[:three_d_secure] && options[:three_d_secure][:eci] || '05'
184
+ post[:sg_IsExternalMPI] = 1
185
+ post[:sg_ExternalTokenProvider] = 5
186
+ end
187
+
168
188
  def add_customer_details(post, payment, options)
169
189
  if address = options[:billing_address] || options[:address]
170
- post[:sg_FirstName] = payment.first_name
171
- post[:sg_LastName] = payment.last_name
190
+ post[:sg_FirstName] = payment.first_name if payment.respond_to?(:first_name)
191
+ post[:sg_LastName] = payment.last_name if payment.respond_to?(:last_name)
172
192
  post[:sg_Address] = address[:address1] if address[:address1]
173
193
  post[:sg_City] = address[:city] if address[:city]
174
194
  post[:sg_State] = address[:state] if address[:state]
@@ -260,11 +260,15 @@ module ActiveMerchant #:nodoc:
260
260
  url = url(params, source)
261
261
  response = parse(ssl_post(url, post_data(action, params)), source)
262
262
 
263
- Response.new(success?(response), response[:message], response,
263
+ Response.new(
264
+ success?(response),
265
+ response[:message],
266
+ response,
264
267
  test: test?,
265
268
  authorization: authorization_from(response, source),
266
269
  avs_result: { code: response[:avs_result] },
267
- cvv_result: response[:cvv_result])
270
+ cvv_result: response[:cvv_result]
271
+ )
268
272
  end
269
273
 
270
274
  def url(params, source)
@@ -380,8 +384,12 @@ module ActiveMerchant #:nodoc:
380
384
  message = success ? 'Succeeded' : 'Failed'
381
385
  end
382
386
 
383
- Response.new(success, message, response,
384
- authorization: response[:guid])
387
+ Response.new(
388
+ success,
389
+ message,
390
+ response,
391
+ authorization: response[:guid]
392
+ )
385
393
  end
386
394
 
387
395
  ENVELOPE_NAMESPACES = {