aktivemerchant 2.0.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 (193) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1596 -0
  3. data/CONTRIBUTORS +511 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +18 -0
  6. data/lib/active_merchant.rb +108 -0
  7. data/lib/active_merchant/billing.rb +13 -0
  8. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  9. data/lib/active_merchant/billing/avs_result.rb +98 -0
  10. data/lib/active_merchant/billing/base.rb +72 -0
  11. data/lib/active_merchant/billing/check.rb +76 -0
  12. data/lib/active_merchant/billing/compatibility.rb +120 -0
  13. data/lib/active_merchant/billing/credit_card.rb +352 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +160 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +268 -0
  18. data/lib/active_merchant/billing/gateways.rb +17 -0
  19. data/lib/active_merchant/billing/gateways/adyen.rb +209 -0
  20. data/lib/active_merchant/billing/gateways/alfabank.rb +117 -0
  21. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net.rb +419 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  24. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  25. data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
  26. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  27. data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
  28. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
  29. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
  30. data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
  31. data/lib/active_merchant/billing/gateways/beanstream.rb +188 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +393 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  34. data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
  35. data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
  36. data/lib/active_merchant/billing/gateways/borgun.rb +210 -0
  37. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  38. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +515 -0
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  42. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  43. data/lib/active_merchant/billing/gateways/card_stream.rb +220 -0
  44. data/lib/active_merchant/billing/gateways/cashnet.rb +191 -0
  45. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  46. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  47. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  48. data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
  49. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  50. data/lib/active_merchant/billing/gateways/conekta.rb +209 -0
  51. data/lib/active_merchant/billing/gateways/cyber_source.rb +709 -0
  52. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  53. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  54. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  55. data/lib/active_merchant/billing/gateways/epay.rb +275 -0
  56. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  57. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  58. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  59. data/lib/active_merchant/billing/gateways/eway_rapid.rb +524 -0
  60. data/lib/active_merchant/billing/gateways/exact.rb +218 -0
  61. data/lib/active_merchant/billing/gateways/fat_zebra.rb +173 -0
  62. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  63. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  64. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  65. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  66. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +355 -0
  67. data/lib/active_merchant/billing/gateways/garanti.rb +257 -0
  68. data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
  69. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  70. data/lib/active_merchant/billing/gateways/hps.rb +288 -0
  71. data/lib/active_merchant/billing/gateways/iats_payments.rb +251 -0
  72. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  73. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  74. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  75. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  76. data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
  77. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  78. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  79. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  80. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  81. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  82. data/lib/active_merchant/billing/gateways/litle.rb +346 -0
  83. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  84. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  85. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  86. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  87. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  88. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  89. data/lib/active_merchant/billing/gateways/mercury.rb +333 -0
  90. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  91. data/lib/active_merchant/billing/gateways/migs.rb +265 -0
  92. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  93. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  94. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  95. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  96. data/lib/active_merchant/billing/gateways/moneris_us.rb +291 -0
  97. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  98. data/lib/active_merchant/billing/gateways/nab_transact.rb +280 -0
  99. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  100. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  101. data/lib/active_merchant/billing/gateways/netbilling.rb +190 -0
  102. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  103. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  104. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  105. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  106. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  107. data/lib/active_merchant/billing/gateways/optimal_payment.rb +313 -0
  108. data/lib/active_merchant/billing/gateways/orbital.rb +803 -0
  109. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  110. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  111. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  112. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +261 -0
  113. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  114. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  115. data/lib/active_merchant/billing/gateways/pay_u_latam.rb +462 -0
  116. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  117. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  118. data/lib/active_merchant/billing/gateways/payflow.rb +304 -0
  119. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +209 -0
  120. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  121. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  122. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  123. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  124. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  125. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  126. data/lib/active_merchant/billing/gateways/paymill.rb +281 -0
  127. data/lib/active_merchant/billing/gateways/paypal.rb +117 -0
  128. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +670 -0
  129. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  130. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  131. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  132. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  133. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  134. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  135. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  136. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  137. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  138. data/lib/active_merchant/billing/gateways/pin.rb +197 -0
  139. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  140. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  141. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  142. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  143. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  144. data/lib/active_merchant/billing/gateways/quickpay.rb +367 -0
  145. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  146. data/lib/active_merchant/billing/gateways/redsys.rb +391 -0
  147. data/lib/active_merchant/billing/gateways/sage.rb +175 -0
  148. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +87 -0
  149. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +114 -0
  150. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  151. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +102 -0
  152. data/lib/active_merchant/billing/gateways/sage_pay.rb +398 -0
  153. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  154. data/lib/active_merchant/billing/gateways/secure_net.rb +252 -0
  155. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  156. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  157. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  158. data/lib/active_merchant/billing/gateways/skip_jack.rb +452 -0
  159. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  160. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  161. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  162. data/lib/active_merchant/billing/gateways/stripe.rb +411 -0
  163. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  164. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  165. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  166. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  167. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  168. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  169. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  170. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  171. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +254 -0
  172. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  173. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  174. data/lib/active_merchant/billing/gateways/vindicia.rb +385 -0
  175. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  176. data/lib/active_merchant/billing/gateways/wepay.rb +189 -0
  177. data/lib/active_merchant/billing/gateways/wirecard.rb +421 -0
  178. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  179. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  180. data/lib/active_merchant/billing/model.rb +30 -0
  181. data/lib/active_merchant/billing/payment_token.rb +21 -0
  182. data/lib/active_merchant/billing/rails.rb +3 -0
  183. data/lib/active_merchant/billing/response.rb +91 -0
  184. data/lib/active_merchant/country.rb +332 -0
  185. data/lib/active_merchant/empty.rb +20 -0
  186. data/lib/active_merchant/errors.rb +29 -0
  187. data/lib/active_merchant/offsite_payments_shim.rb +19 -0
  188. data/lib/active_merchant/version.rb +3 -0
  189. data/lib/activemerchant.rb +1 -0
  190. data/lib/support/gateway_support.rb +71 -0
  191. data/lib/support/outbound_hosts.rb +25 -0
  192. data/lib/support/ssl_verify.rb +93 -0
  193. metadata +400 -0
@@ -0,0 +1,391 @@
1
+ # coding: utf-8
2
+ require 'nokogiri'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ # = Redsys Merchant Gateway
7
+ #
8
+ # Gateway support for the Spanish "Redsys" payment gateway system. This is
9
+ # used by many banks in Spain and is particularly well supported by
10
+ # Catalunya Caixa's ecommerce department.
11
+ #
12
+ # Redsys requires an order_id be provided with each transaction and it must
13
+ # follow a specific format. The rules are as follows:
14
+ #
15
+ # * First 4 digits must be numerical
16
+ # * Remaining 8 digits may be alphanumeric
17
+ # * Max length: 12
18
+ #
19
+ # If an invalid order_id is provided, we do our best to clean it up.
20
+ #
21
+ # Much of the code for this library is based on the active_merchant_sermepa
22
+ # integration gateway which uses essentially the same API but with the
23
+ # banks own payment screen.
24
+ #
25
+ # Written by Samuel Lown for Cabify. For implementation questions, or
26
+ # test access details please get in touch: sam@cabify.com.
27
+ class RedsysGateway < Gateway
28
+ self.live_url = "https://sis.sermepa.es/sis/operaciones"
29
+ self.test_url = "https://sis-t.sermepa.es:25443/sis/operaciones"
30
+
31
+ self.supported_countries = ['ES']
32
+ self.default_currency = 'EUR'
33
+ self.money_format = :cents
34
+
35
+ # Not all card types may be activated by the bank!
36
+ self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :diners_club]
37
+ self.homepage_url = "http://www.redsys.es/"
38
+ self.display_name = "Redsys"
39
+
40
+ CURRENCY_CODES = {
41
+ "ARS" => '032',
42
+ "AUD" => '036',
43
+ "BRL" => '986',
44
+ "BOB" => '068',
45
+ "CAD" => '124',
46
+ "CHF" => '756',
47
+ "CLP" => '152',
48
+ "COP" => '170',
49
+ "EUR" => '978',
50
+ "GBP" => '826',
51
+ "GTQ" => '320',
52
+ "JPY" => '392',
53
+ "MXN" => '484',
54
+ "NZD" => '554',
55
+ "PEN" => '604',
56
+ "RUB" => '643',
57
+ "SGD" => '702',
58
+ "USD" => '840',
59
+ "UYU" => '858'
60
+ }
61
+
62
+ # The set of supported transactions for this gateway.
63
+ # More operations are supported by the gateway itself, but
64
+ # are not supported in this library.
65
+ SUPPORTED_TRANSACTIONS = {
66
+ :purchase => 'A',
67
+ :authorize => '1',
68
+ :capture => '2',
69
+ :refund => '3',
70
+ :cancel => '9'
71
+ }
72
+
73
+ # These are the text meanings sent back by the acquirer when
74
+ # a card has been rejected. Syntax or general request errors
75
+ # are not covered here.
76
+ RESPONSE_TEXTS = {
77
+ 0 => "Transaction Approved",
78
+ 400 => "Cancellation Accepted",
79
+ 481 => "Cancellation Accepted",
80
+ 500 => "Reconciliation Accepted",
81
+ 900 => "Refund / Confirmation approved",
82
+
83
+ 101 => "Card expired",
84
+ 102 => "Card blocked temporarily or under susciption of fraud",
85
+ 104 => "Transaction not permitted",
86
+ 107 => "Contact the card issuer",
87
+ 109 => "Invalid identification by merchant or POS terminal",
88
+ 110 => "Invalid amount",
89
+ 114 => "Card cannot be used to the requested transaction",
90
+ 116 => "Insufficient credit",
91
+ 118 => "Non-registered card",
92
+ 125 => "Card not effective",
93
+ 129 => "CVV2/CVC2 Error",
94
+ 167 => "Contact the card issuer: suspected fraud",
95
+ 180 => "Card out of service",
96
+ 181 => "Card with credit or debit restrictions",
97
+ 182 => "Card with credit or debit restrictions",
98
+ 184 => "Authentication error",
99
+ 190 => "Refusal with no specific reason",
100
+ 191 => "Expiry date incorrect",
101
+
102
+ 201 => "Card expired",
103
+ 202 => "Card blocked temporarily or under suscipition of fraud",
104
+ 204 => "Transaction not permitted",
105
+ 207 => "Contact the card issuer",
106
+ 208 => "Lost or stolen card",
107
+ 209 => "Lost or stolen card",
108
+ 280 => "CVV2/CVC2 Error",
109
+ 290 => "Declined with no specific reason",
110
+
111
+ 480 => "Original transaction not located, or time-out exceeded",
112
+ 501 => "Original transaction not located, or time-out exceeded",
113
+ 502 => "Original transaction not located, or time-out exceeded",
114
+ 503 => "Original transaction not located, or time-out exceeded",
115
+
116
+ 904 => "Merchant not registered at FUC",
117
+ 909 => "System error",
118
+ 912 => "Issuer not available",
119
+ 913 => "Duplicate transmission",
120
+ 916 => "Amount too low",
121
+ 928 => "Time-out exceeded",
122
+ 940 => "Transaction cancelled previously",
123
+ 941 => "Authorization operation already cancelled",
124
+ 942 => "Original authorization declined",
125
+ 943 => "Different details from origin transaction",
126
+ 944 => "Session error",
127
+ 945 => "Duplicate transmission",
128
+ 946 => "Cancellation of transaction while in progress",
129
+ 947 => "Duplicate tranmission while in progress",
130
+ 949 => "POS Inoperative",
131
+ 950 => "Refund not possible",
132
+ 9064 => "Card number incorrect",
133
+ 9078 => "No payment method available",
134
+ 9093 => "Non-existent card",
135
+ 9218 => "Recursive transaction in bad gateway",
136
+ 9253 => "Check-digit incorrect",
137
+ 9256 => "Preauth not allowed for merchant",
138
+ 9257 => "Preauth not allowed for card",
139
+ 9261 => "Operating limit exceeded",
140
+ 9912 => "Issuer not available",
141
+ 9913 => "Confirmation error",
142
+ 9914 => "KO Confirmation"
143
+ }
144
+
145
+ # Creates a new instance
146
+ #
147
+ # Redsys requires a login and secret_key, and optionally also accepts a
148
+ # non-default terminal.
149
+ #
150
+ # ==== Options
151
+ #
152
+ # * <tt>:login</tt> -- The Redsys Merchant ID (REQUIRED)
153
+ # * <tt>:secret_key</tt> -- The Redsys Secret Key. (REQUIRED)
154
+ # * <tt>:terminal</tt> -- The Redsys Terminal. Defaults to 1. (OPTIONAL)
155
+ # * <tt>:test</tt> -- +true+ or +false+. Defaults to +false+. (OPTIONAL)
156
+ def initialize(options = {})
157
+ requires!(options, :login, :secret_key)
158
+ options[:terminal] ||= 1
159
+ super
160
+ end
161
+
162
+ def purchase(money, creditcard, options = {})
163
+ requires!(options, :order_id)
164
+
165
+ data = {}
166
+ add_action(data, :purchase)
167
+ add_amount(data, money, options)
168
+ add_order(data, options[:order_id])
169
+ add_creditcard(data, creditcard)
170
+ data[:description] = options[:description]
171
+
172
+ commit data
173
+ end
174
+
175
+ def authorize(money, creditcard, options = {})
176
+ requires!(options, :order_id)
177
+
178
+ data = {}
179
+ add_action(data, :authorize)
180
+ add_amount(data, money, options)
181
+ add_order(data, options[:order_id])
182
+ add_creditcard(data, creditcard)
183
+ data[:description] = options[:description]
184
+
185
+ commit data
186
+ end
187
+
188
+ def capture(money, authorization, options = {})
189
+ data = {}
190
+ add_action(data, :capture)
191
+ add_amount(data, money, options)
192
+ order_id, _, _ = split_authorization(authorization)
193
+ add_order(data, order_id)
194
+ data[:description] = options[:description]
195
+
196
+ commit data
197
+ end
198
+
199
+ def void(authorization, options = {})
200
+ data = {}
201
+ add_action(data, :cancel)
202
+ order_id, amount, currency = split_authorization(authorization)
203
+ add_amount(data, amount, :currency => currency)
204
+ add_order(data, order_id)
205
+ data[:description] = options[:description]
206
+
207
+ commit data
208
+ end
209
+
210
+ def refund(money, authorization, options = {})
211
+ data = {}
212
+ add_action(data, :refund)
213
+ add_amount(data, money, options)
214
+ order_id, _, _ = split_authorization(authorization)
215
+ add_order(data, order_id)
216
+ data[:description] = options[:description]
217
+
218
+ commit data
219
+ end
220
+
221
+ def verify(creditcard, options = {})
222
+ MultiResponse.run(:use_first_response) do |r|
223
+ r.process { authorize(100, creditcard, options) }
224
+ r.process(:ignore_result) { void(r.authorization, options) }
225
+ end
226
+ end
227
+
228
+ private
229
+
230
+ def add_action(data, action)
231
+ data[:action] = transaction_code(action)
232
+ end
233
+
234
+ def add_amount(data, money, options)
235
+ data[:amount] = amount(money).to_s
236
+ data[:currency] = currency_code(options[:currency] || currency(money))
237
+ end
238
+
239
+ def add_order(data, order_id)
240
+ data[:order_id] = clean_order_id(order_id)
241
+ end
242
+
243
+ def url
244
+ test? ? test_url : live_url
245
+ end
246
+
247
+ def add_creditcard(data, card)
248
+ name = [card.first_name, card.last_name].join(' ').slice(0, 60)
249
+ year = sprintf("%.4i", card.year)
250
+ month = sprintf("%.2i", card.month)
251
+ data[:card] = {
252
+ :name => name,
253
+ :pan => card.number,
254
+ :date => "#{year[2..3]}#{month}",
255
+ :cvv => card.verification_value
256
+ }
257
+ end
258
+
259
+ def commit(data)
260
+ headers = {
261
+ 'Content-Type' => 'application/x-www-form-urlencoded'
262
+ }
263
+ xml = build_xml_request(data)
264
+ parse(ssl_post(url, "entrada=#{CGI.escape(xml)}", headers))
265
+ end
266
+
267
+ def build_signature(data)
268
+ str = data[:amount] +
269
+ data[:order_id].to_s +
270
+ @options[:login].to_s +
271
+ data[:currency]
272
+
273
+ if card = data[:card]
274
+ str << card[:pan]
275
+ str << card[:cvv] if card[:cvv]
276
+ end
277
+
278
+ str << data[:action]
279
+ str << @options[:secret_key]
280
+
281
+ Digest::SHA1.hexdigest(str)
282
+ end
283
+
284
+ def build_xml_request(data)
285
+ xml = Builder::XmlMarkup.new :indent => 2
286
+ xml.DATOSENTRADA do
287
+ # Basic elements
288
+ xml.DS_Version 0.1
289
+ xml.DS_MERCHANT_CURRENCY data[:currency]
290
+ xml.DS_MERCHANT_AMOUNT data[:amount]
291
+ xml.DS_MERCHANT_ORDER data[:order_id]
292
+ xml.DS_MERCHANT_TRANSACTIONTYPE data[:action]
293
+ xml.DS_MERCHANT_PRODUCTDESCRIPTION data[:description]
294
+ xml.DS_MERCHANT_TERMINAL @options[:terminal]
295
+ xml.DS_MERCHANT_MERCHANTCODE @options[:login]
296
+ xml.DS_MERCHANT_MERCHANTSIGNATURE build_signature(data)
297
+
298
+ # Only when card is present
299
+ if data[:card]
300
+ xml.DS_MERCHANT_TITULAR data[:card][:name]
301
+ xml.DS_MERCHANT_PAN data[:card][:pan]
302
+ xml.DS_MERCHANT_EXPIRYDATE data[:card][:date]
303
+ xml.DS_MERCHANT_CVV2 data[:card][:cvv]
304
+ end
305
+ end
306
+ xml.target!
307
+ end
308
+
309
+ def parse(data)
310
+ params = {}
311
+ success = false
312
+ message = ""
313
+ options = @options.merge(:test => test?)
314
+ xml = Nokogiri::XML(data)
315
+ code = xml.xpath("//RETORNOXML/CODIGO").text
316
+ if code == "0"
317
+ op = xml.xpath("//RETORNOXML/OPERACION")
318
+ op.children.each do |element|
319
+ params[element.name.downcase.to_sym] = element.text
320
+ end
321
+
322
+ if validate_signature(params)
323
+ message = response_text(params[:ds_response])
324
+ options[:authorization] = build_authorization(params)
325
+ success = is_success_response?(params[:ds_response])
326
+ else
327
+ message = "Response failed validation check"
328
+ end
329
+ else
330
+ # Some kind of programmer error with the request!
331
+ message = "#{code} ERROR"
332
+ end
333
+
334
+ Response.new(success, message, params, options)
335
+ end
336
+
337
+ def validate_signature(data)
338
+ str = data[:ds_amount] +
339
+ data[:ds_order].to_s +
340
+ data[:ds_merchantcode] +
341
+ data[:ds_currency] +
342
+ data[:ds_response] +
343
+ data[:ds_cardnumber].to_s +
344
+ data[:ds_transactiontype].to_s +
345
+ data[:ds_securepayment].to_s +
346
+ @options[:secret_key]
347
+
348
+ sig = Digest::SHA1.hexdigest(str)
349
+ data[:ds_signature].to_s.downcase == sig
350
+ end
351
+
352
+ def build_authorization(params)
353
+ [params[:ds_order], params[:ds_amount], params[:ds_currency]].join("|")
354
+ end
355
+
356
+ def split_authorization(authorization)
357
+ order_id, amount, currency = authorization.split("|")
358
+ [order_id, amount.to_i, currency]
359
+ end
360
+
361
+ def currency_code(currency)
362
+ return currency if currency =~ /^\d+$/
363
+ raise ArgumentError, "Unknown currency #{currency}" unless CURRENCY_CODES[currency]
364
+ CURRENCY_CODES[currency]
365
+ end
366
+
367
+ def transaction_code(type)
368
+ SUPPORTED_TRANSACTIONS[type]
369
+ end
370
+
371
+ def response_text(code)
372
+ code = code.to_i
373
+ code = 0 if code < 100
374
+ RESPONSE_TEXTS[code] || "Unkown code, please check in manual"
375
+ end
376
+
377
+ def is_success_response?(code)
378
+ (code.to_i < 100) || [400, 481, 500, 900].include?(code.to_i)
379
+ end
380
+
381
+ def clean_order_id(order_id)
382
+ cleansed = order_id.gsub(/[^\da-zA-Z]/, '')
383
+ if cleansed =~ /^\d{4}/
384
+ cleansed[0..12]
385
+ else
386
+ "%04d%s" % [rand(0..9999), cleansed[0...8]]
387
+ end
388
+ end
389
+ end
390
+ end
391
+ end
@@ -0,0 +1,175 @@
1
+ require File.dirname(__FILE__) + '/sage/sage_bankcard'
2
+ require File.dirname(__FILE__) + '/sage/sage_virtual_check'
3
+ require File.dirname(__FILE__) + '/sage/sage_vault'
4
+
5
+ module ActiveMerchant #:nodoc:
6
+ module Billing #:nodoc:
7
+ class SageGateway < Gateway
8
+ self.supported_countries = SageBankcardGateway.supported_countries
9
+ self.supported_cardtypes = SageBankcardGateway.supported_cardtypes
10
+
11
+ self.abstract_class = true
12
+
13
+ # Creates a new SageGateway
14
+ #
15
+ # The gateway requires that a valid login and password be passed
16
+ # in the +options+ hash.
17
+ #
18
+ # ==== Options
19
+ #
20
+ # * <tt>:login</tt> - The Sage Payment Solutions Merchant ID Number.
21
+ # * <tt>:password</tt> - The Sage Payment Solutions Merchant Key Number.
22
+ def initialize(options = {})
23
+ requires!(options, :login, :password)
24
+ super
25
+ end
26
+
27
+ # Performs an authorization transaction
28
+ #
29
+ # ==== Parameters
30
+ # * <tt>money</tt> - The amount to be authorized as an integer value in cents.
31
+ # * <tt>credit_card</tt> - The CreditCard object to be used as the funding source for the transaction.
32
+ # * <tt>options</tt> - A hash of optional parameters.
33
+ # * <tt>:order_id</tt> - A unique reference for this order. (maximum of 20 characters).
34
+ # * <tt>:email</tt> - The customer's email address
35
+ # * <tt>:customer</tt> - The Customer Number for Purchase Card Level II Transactions
36
+ # * <tt>:billing_address</tt> - The customer's billing address as a hash of address information.
37
+ # * <tt>:address1</tt> - The billing address street
38
+ # * <tt>:city</tt> - The billing address city
39
+ # * <tt>:state</tt> - The billing address state
40
+ # * <tt>:country</tt> - The 2 digit ISO billing address country code
41
+ # * <tt>:zip</tt> - The billing address zip code
42
+ # * <tt>:phone</tt> - The billing address phone number
43
+ # * <tt>:fax</tt> - The billing address fax number
44
+ # * <tt>:shipping_address</tt> - The customer's shipping address as a hash of address information.
45
+ # * <tt>:name</tt> - The name at the shipping address
46
+ # * <tt>:address1</tt> - The shipping address street
47
+ # * <tt>:city</tt> - The shipping address city
48
+ # * <tt>:state</tt> - The shipping address state code
49
+ # * <tt>:country</tt> - The 2 digit ISO shipping address country code
50
+ # * <tt>:zip</tt> - The shipping address zip code
51
+ # * <tt>:tax</tt> - The tax amount for the transaction as an Integer value in cents. Maps to Sage <tt>T_tax</tt>.
52
+ # * <tt>:shipping</tt> - The shipping amount for the transaction as an Integer value in cents. Maps to Sage <tt>T_shipping</tt>.
53
+ def authorize(money, credit_card, options = {})
54
+ bankcard.authorize(money, credit_card, options)
55
+ end
56
+
57
+ # Performs a purchase, which is essentially an authorization and capture in a single operation.
58
+ #
59
+ # ==== Parameters
60
+ #
61
+ # * <tt>money</tt> - The amount to be authorized as an integer value in cents.
62
+ # * <tt>source</tt> - The CreditCard or Check object to be used as the funding source for the transaction.
63
+ # * <tt>options</tt> - A hash of optional parameters.
64
+ # * <tt>:order_id</tt> - A unique reference for this order. (maximum of 20 characters).
65
+ # * <tt>:email</tt> - The customer's email address
66
+ # * <tt>:customer</tt> - The Customer Number for Purchase Card Level II Transactions
67
+ # * <tt>:billing_address</tt> - The customer's billing address as a hash of address information.
68
+ # * <tt>:address1</tt> - The billing address street
69
+ # * <tt>:city</tt> - The billing address city
70
+ # * <tt>:state</tt> - The billing address state
71
+ # * <tt>:country</tt> - The 2 digit ISO billing address country code
72
+ # * <tt>:zip</tt> - The billing address zip code
73
+ # * <tt>:phone</tt> - The billing address phone number
74
+ # * <tt>:fax</tt> - The billing address fax number
75
+ # * <tt>:shipping_address</tt> - The customer's shipping address as a hash of address information.
76
+ # * <tt>:name</tt> - The name at the shipping address
77
+ # * <tt>:address1</tt> - The shipping address street
78
+ # * <tt>:city</tt> - The shipping address city
79
+ # * <tt>:state</tt> - The shipping address state code
80
+ # * <tt>:country</tt> - The 2 digit ISO shipping address country code
81
+ # * <tt>:zip</tt> - The shipping address zip code
82
+ # * <tt>:tax</tt> - The tax amount for the transaction as an integer value in cents. Maps to Sage <tt>T_tax</tt>.
83
+ # * <tt>:shipping</tt> - The shipping amount for the transaction as an integer value in cents. Maps to Sage <tt>T_shipping</tt>.
84
+ #
85
+ # ==== Additional options in the +options+ hash for when using a Check as the funding source
86
+ # * <tt>:originator_id</tt> - 10 digit originator. If not provided, Sage will use the default Originator ID for the specific customer type.
87
+ # * <tt>:addenda</tt> - Transaction addenda.
88
+ # * <tt>:ssn</tt> - The customer's Social Security Number.
89
+ # * <tt>:drivers_license_state</tt> - The customer's drivers license state code.
90
+ # * <tt>:drivers_license_number</tt> - The customer's drivers license number.
91
+ # * <tt>:date_of_birth</tt> - The customer's date of birth as a Time or Date object or a string in the format <tt>mm/dd/yyyy</tt>.
92
+ def purchase(money, source, options = {})
93
+ if card_brand(source) == "check"
94
+ virtual_check.purchase(money, source, options)
95
+ else
96
+ bankcard.purchase(money, source, options)
97
+ end
98
+ end
99
+
100
+ # Captures authorized funds.
101
+ #
102
+ # ==== Parameters
103
+ #
104
+ # * <tt>money</tt> - The amount to be authorized as an integer value in cents. Sage doesn't support changing the capture amount, so the full amount of the initial transaction will be captured.
105
+ # * <tt>reference</tt> - The authorization reference string returned by the original transaction's Response#authorization.
106
+ def capture(money, reference, options = {})
107
+ bankcard.capture(money, reference, options)
108
+ end
109
+
110
+ # Voids a prior transaction. Works for both CreditCard and Check transactions.
111
+ #
112
+ # ==== Parameters
113
+ #
114
+ # * <tt>reference</tt> - The authorization reference string returned by the original transaction's Response#authorization.
115
+ def void(reference, options = {})
116
+ if reference.split(";").last == "virtual_check"
117
+ virtual_check.void(reference, options)
118
+ else
119
+ bankcard.void(reference, options)
120
+ end
121
+ end
122
+
123
+ def credit(money, source, options = {})
124
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
125
+ refund(money, source, options)
126
+ end
127
+
128
+ # Performs a refund transaction.
129
+ #
130
+ # ==== Parameters
131
+ #
132
+ # * <tt>money</tt> - The amount to be authorized as an integer value in cents.
133
+ # * <tt>source</tt> - The CreditCard or Check object to be used as the target for the refund.
134
+ def refund(money, source, options = {})
135
+ if card_brand(source) == "check"
136
+ virtual_check.refund(money, source, options)
137
+ else
138
+ bankcard.refund(money, source, options)
139
+ end
140
+ end
141
+
142
+ # Stores a credit card in the Sage vault.
143
+ #
144
+ # ==== Parameters
145
+ #
146
+ # * <tt>credit_card</tt> - The CreditCard object to be stored.
147
+ def store(credit_card, options = {})
148
+ vault.store(credit_card, options)
149
+ end
150
+
151
+ # Deletes a stored card from the Sage vault.
152
+ #
153
+ # ==== Parameters
154
+ #
155
+ # * <tt>identification</tt> - The 'GUID' identifying the stored card.
156
+ def unstore(identification, options = {})
157
+ vault.unstore(identification, options)
158
+ end
159
+
160
+ private
161
+
162
+ def bankcard
163
+ @bankcard ||= SageBankcardGateway.new(@options)
164
+ end
165
+
166
+ def virtual_check
167
+ @virtual_check ||= SageVirtualCheckGateway.new(@options)
168
+ end
169
+
170
+ def vault
171
+ @vault ||= SageVaultGateway.new(@options)
172
+ end
173
+ end
174
+ end
175
+ end