activemerchant 1.130.0 → 1.137.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +268 -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 +13 -8
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +64 -7
  8. data/lib/active_merchant/billing/gateway.rb +9 -0
  9. data/lib/active_merchant/billing/gateways/adyen.rb +240 -41
  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 +44 -36
  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/borgun.rb +6 -4
  21. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +65 -20
  22. data/lib/active_merchant/billing/gateways/braintree_blue.rb +226 -73
  23. data/lib/active_merchant/billing/gateways/braintree_orange.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/card_connect.rb +5 -2
  25. data/lib/active_merchant/billing/gateways/card_stream.rb +4 -6
  26. data/lib/active_merchant/billing/gateways/cashnet.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/cecabank/cecabank_common.rb +36 -0
  28. data/lib/active_merchant/billing/gateways/cecabank/cecabank_json.rb +316 -0
  29. data/lib/active_merchant/billing/gateways/cecabank/cecabank_xml.rb +220 -0
  30. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -240
  31. data/lib/active_merchant/billing/gateways/checkout_v2.rb +252 -41
  32. data/lib/active_merchant/billing/gateways/commerce_hub.rb +69 -8
  33. data/lib/active_merchant/billing/gateways/credorax.rb +3 -5
  34. data/lib/active_merchant/billing/gateways/cyber_source.rb +192 -41
  35. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +102 -58
  36. data/lib/active_merchant/billing/gateways/d_local.rb +26 -15
  37. data/lib/active_merchant/billing/gateways/data_cash.rb +21 -17
  38. data/lib/active_merchant/billing/gateways/datatrans.rb +279 -0
  39. data/lib/active_merchant/billing/gateways/decidir.rb +53 -18
  40. data/lib/active_merchant/billing/gateways/decidir_plus.rb +4 -1
  41. data/lib/active_merchant/billing/gateways/deepstack.rb +382 -0
  42. data/lib/active_merchant/billing/gateways/ebanx.rb +40 -36
  43. data/lib/active_merchant/billing/gateways/efsnet.rb +6 -2
  44. data/lib/active_merchant/billing/gateways/elavon.rb +99 -33
  45. data/lib/active_merchant/billing/gateways/element.rb +36 -7
  46. data/lib/active_merchant/billing/gateways/epay.rb +6 -2
  47. data/lib/active_merchant/billing/gateways/evo_ca.rb +6 -2
  48. data/lib/active_merchant/billing/gateways/eway.rb +4 -2
  49. data/lib/active_merchant/billing/gateways/eway_managed.rb +6 -2
  50. data/lib/active_merchant/billing/gateways/exact.rb +6 -2
  51. data/lib/active_merchant/billing/gateways/fat_zebra.rb +31 -3
  52. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -2
  53. data/lib/active_merchant/billing/gateways/first_pay/first_pay_common.rb +15 -0
  54. data/lib/active_merchant/billing/gateways/first_pay/first_pay_json.rb +190 -0
  55. data/lib/active_merchant/billing/gateways/first_pay/first_pay_xml.rb +183 -0
  56. data/lib/active_merchant/billing/gateways/first_pay.rb +6 -172
  57. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -2
  58. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +7 -3
  59. data/lib/active_merchant/billing/gateways/flex_charge.rb +347 -0
  60. data/lib/active_merchant/billing/gateways/garanti.rb +4 -2
  61. data/lib/active_merchant/billing/gateways/global_collect.rb +45 -37
  62. data/lib/active_merchant/billing/gateways/hi_pay.rb +286 -0
  63. data/lib/active_merchant/billing/gateways/hps.rb +1 -1
  64. data/lib/active_merchant/billing/gateways/iats_payments.rb +7 -2
  65. data/lib/active_merchant/billing/gateways/inspire.rb +6 -4
  66. data/lib/active_merchant/billing/gateways/instapay.rb +7 -4
  67. data/lib/active_merchant/billing/gateways/ipg.rb +10 -6
  68. data/lib/active_merchant/billing/gateways/iridium.rb +15 -5
  69. data/lib/active_merchant/billing/gateways/itransact.rb +6 -2
  70. data/lib/active_merchant/billing/gateways/iveri.rb +3 -3
  71. data/lib/active_merchant/billing/gateways/ixopay.rb +2 -2
  72. data/lib/active_merchant/billing/gateways/jetpay.rb +4 -2
  73. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +4 -2
  74. data/lib/active_merchant/billing/gateways/kushki.rb +73 -13
  75. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -2
  76. data/lib/active_merchant/billing/gateways/litle.rb +33 -50
  77. data/lib/active_merchant/billing/gateways/mastercard.rb +4 -4
  78. data/lib/active_merchant/billing/gateways/maxipago.rb +2 -2
  79. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +8 -5
  80. data/lib/active_merchant/billing/gateways/merchant_ware.rb +11 -4
  81. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +11 -4
  82. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +19 -3
  83. data/lib/active_merchant/billing/gateways/mercury.rb +6 -2
  84. data/lib/active_merchant/billing/gateways/metrics_global.rb +8 -6
  85. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +1 -0
  86. data/lib/active_merchant/billing/gateways/migs.rb +6 -2
  87. data/lib/active_merchant/billing/gateways/mit.rb +25 -20
  88. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +18 -10
  89. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  90. data/lib/active_merchant/billing/gateways/moneris.rb +9 -3
  91. data/lib/active_merchant/billing/gateways/money_movers.rb +6 -2
  92. data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -4
  93. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -2
  94. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -3
  95. data/lib/active_merchant/billing/gateways/netbilling.rb +6 -2
  96. data/lib/active_merchant/billing/gateways/network_merchants.rb +6 -2
  97. data/lib/active_merchant/billing/gateways/nmi.rb +23 -6
  98. data/lib/active_merchant/billing/gateways/ogone.rb +6 -2
  99. data/lib/active_merchant/billing/gateways/openpay.rb +4 -2
  100. data/lib/active_merchant/billing/gateways/opp.rb +1 -2
  101. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -2
  102. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +1 -3
  103. data/lib/active_merchant/billing/gateways/orbital.rb +83 -24
  104. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +7 -4
  105. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +6 -2
  106. data/lib/active_merchant/billing/gateways/pay_hub.rb +4 -2
  107. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -2
  108. data/lib/active_merchant/billing/gateways/pay_secure.rb +6 -2
  109. data/lib/active_merchant/billing/gateways/pay_trace.rb +31 -18
  110. data/lib/active_merchant/billing/gateways/payeezy.rb +19 -8
  111. data/lib/active_merchant/billing/gateways/payex.rb +4 -2
  112. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  113. data/lib/active_merchant/billing/gateways/payflow.rb +1 -3
  114. data/lib/active_merchant/billing/gateways/payment_express.rb +8 -4
  115. data/lib/active_merchant/billing/gateways/paymentez.rb +23 -11
  116. data/lib/active_merchant/billing/gateways/paysafe.rb +12 -11
  117. data/lib/active_merchant/billing/gateways/payscout.rb +7 -4
  118. data/lib/active_merchant/billing/gateways/paystation.rb +7 -3
  119. data/lib/active_merchant/billing/gateways/payway.rb +6 -2
  120. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
  121. data/lib/active_merchant/billing/gateways/pin.rb +22 -4
  122. data/lib/active_merchant/billing/gateways/plexo.rb +49 -10
  123. data/lib/active_merchant/billing/gateways/plugnpay.rb +6 -2
  124. data/lib/active_merchant/billing/gateways/priority.rb +6 -5
  125. data/lib/active_merchant/billing/gateways/psigate.rb +6 -2
  126. data/lib/active_merchant/billing/gateways/psl_card.rb +6 -2
  127. data/lib/active_merchant/billing/gateways/qbms.rb +6 -2
  128. data/lib/active_merchant/billing/gateways/quantum.rb +6 -2
  129. data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -5
  130. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -4
  131. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +6 -2
  132. data/lib/active_merchant/billing/gateways/rapyd.rb +148 -46
  133. data/lib/active_merchant/billing/gateways/reach.rb +11 -4
  134. data/lib/active_merchant/billing/gateways/redsys.rb +3 -11
  135. data/lib/active_merchant/billing/gateways/redsys_rest.rb +507 -0
  136. data/lib/active_merchant/billing/gateways/s5.rb +3 -3
  137. data/lib/active_merchant/billing/gateways/safe_charge.rb +38 -17
  138. data/lib/active_merchant/billing/gateways/sage.rb +12 -4
  139. data/lib/active_merchant/billing/gateways/sage_pay.rb +79 -5
  140. data/lib/active_merchant/billing/gateways/sallie_mae.rb +6 -2
  141. data/lib/active_merchant/billing/gateways/secure_net.rb +6 -2
  142. data/lib/active_merchant/billing/gateways/secure_pay.rb +8 -6
  143. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -4
  144. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +6 -2
  145. data/lib/active_merchant/billing/gateways/securion_pay.rb +24 -10
  146. data/lib/active_merchant/billing/gateways/shift4.rb +17 -20
  147. data/lib/active_merchant/billing/gateways/shift4_v2.rb +117 -0
  148. data/lib/active_merchant/billing/gateways/simetrik.rb +17 -11
  149. data/lib/active_merchant/billing/gateways/skip_jack.rb +6 -2
  150. data/lib/active_merchant/billing/gateways/smart_ps.rb +7 -4
  151. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +4 -2
  152. data/lib/active_merchant/billing/gateways/spreedly_core.rb +2 -4
  153. data/lib/active_merchant/billing/gateways/stripe.rb +63 -19
  154. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +280 -88
  155. data/lib/active_merchant/billing/gateways/sum_up.rb +223 -0
  156. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +4 -2
  157. data/lib/active_merchant/billing/gateways/telr.rb +3 -4
  158. data/lib/active_merchant/billing/gateways/trans_first.rb +1 -2
  159. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +8 -16
  160. data/lib/active_merchant/billing/gateways/transact_pro.rb +1 -1
  161. data/lib/active_merchant/billing/gateways/trust_commerce.rb +6 -2
  162. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -8
  163. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -2
  164. data/lib/active_merchant/billing/gateways/vanco.rb +2 -4
  165. data/lib/active_merchant/billing/gateways/vantiv_express.rb +587 -0
  166. data/lib/active_merchant/billing/gateways/verifi.rb +6 -2
  167. data/lib/active_merchant/billing/gateways/viaklix.rb +6 -2
  168. data/lib/active_merchant/billing/gateways/visanet_peru.rb +2 -2
  169. data/lib/active_merchant/billing/gateways/vpos.rb +4 -4
  170. data/lib/active_merchant/billing/gateways/wirecard.rb +7 -3
  171. data/lib/active_merchant/billing/gateways/wompi.rb +5 -0
  172. data/lib/active_merchant/billing/gateways/worldpay.rb +147 -93
  173. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +13 -10
  174. data/lib/active_merchant/billing/gateways/xpay.rb +242 -0
  175. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  176. data/lib/active_merchant/billing/response.rb +2 -2
  177. data/lib/active_merchant/connection.rb +3 -17
  178. data/lib/active_merchant/country.rb +1 -0
  179. data/lib/active_merchant/errors.rb +10 -0
  180. data/lib/active_merchant/version.rb +1 -1
  181. data/lib/support/gateway_support.rb +2 -2
  182. data/lib/support/ssl_verify.rb +4 -4
  183. data/lib/support/ssl_version.rb +6 -6
  184. metadata +30 -9
@@ -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
 
@@ -73,10 +73,10 @@ module ActiveMerchant #:nodoc:
73
73
  add_transaction_data('Credit', post, money, options.merge!({ currency: original_currency }))
74
74
  post[:sg_CreditType] = 2
75
75
  post[:sg_AuthCode] = auth
76
- post[:sg_TransactionID] = transaction_id
77
76
  post[:sg_CCToken] = token
78
77
  post[:sg_ExpMonth] = exp_month
79
78
  post[:sg_ExpYear] = exp_year
79
+ post[:sg_TransactionID] = transaction_id unless options[:unreferenced_refund]
80
80
 
81
81
  commit(post)
82
82
  end
@@ -86,8 +86,9 @@ module ActiveMerchant #:nodoc:
86
86
 
87
87
  add_payment(post, payment, options)
88
88
  add_transaction_data('Credit', post, money, options)
89
+ add_customer_details(post, payment, options)
89
90
 
90
- post[:sg_CreditType] = 1
91
+ options[:unreferenced_refund].to_s == 'true' ? post[:sg_CreditType] = 2 : post[:sg_CreditType] = 1
91
92
 
92
93
  commit(post)
93
94
  end
@@ -148,26 +149,46 @@ module ActiveMerchant #:nodoc:
148
149
  end
149
150
 
150
151
  def add_payment(post, payment, options = {})
151
- post[:sg_ExpMonth] = format(payment.month, :two_digits)
152
- post[:sg_ExpYear] = format(payment.year, :two_digits)
153
- post[:sg_CardNumber] = payment.number
154
-
155
- if payment.is_a?(NetworkTokenizationCreditCard) && payment.source == :network_token
156
- post[:sg_CAVV] = payment.payment_cryptogram
157
- post[:sg_ECI] = options[:three_d_secure] && options[:three_d_secure][:eci] || '05'
158
- post[:sg_IsExternalMPI] = 1
159
- post[:sg_ExternalTokenProvider] = 5
160
- else
161
- post[:sg_CVV2] = payment.verification_value
162
- post[:sg_NameOnCard] = payment.name
163
- 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
164
165
  end
165
166
  end
166
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
+
167
188
  def add_customer_details(post, payment, options)
168
189
  if address = options[:billing_address] || options[:address]
169
- post[:sg_FirstName] = payment.first_name
170
- 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)
171
192
  post[:sg_Address] = address[:address1] if address[:address1]
172
193
  post[:sg_City] = address[:city] if address[:city]
173
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 = {