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,219 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+
6
+ class EfsnetGateway < Gateway
7
+ self.supported_countries = ['US']
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
9
+ self.homepage_url = 'http://www.concordefsnet.com/'
10
+ self.display_name = 'Efsnet'
11
+
12
+ self.test_url = 'https://testefsnet.concordebiz.com/efsnet.dll'
13
+ self.live_url = 'https://efsnet.concordebiz.com/efsnet.dll'
14
+
15
+ # login is your Store ID
16
+ # password is your Store Key
17
+ def initialize(options = {})
18
+ requires!(options, :login, :password)
19
+ super
20
+ end
21
+
22
+ def authorize(money, creditcard, options = {})
23
+ request = build_credit_card_request(money, creditcard, options)
24
+ commit(:credit_card_authorize, request)
25
+ end
26
+
27
+ def purchase(money, creditcard, options = {})
28
+ request = build_credit_card_request(money, creditcard, options)
29
+ commit(:credit_card_charge, request)
30
+ end
31
+
32
+ def capture(money, identification, options = {})
33
+ request = build_refund_or_settle_request(money, identification, options)
34
+ commit(:credit_card_settle, request)
35
+ end
36
+
37
+ def credit(money, identification_or_credit_card, options = {})
38
+ if identification_or_credit_card.is_a?(String)
39
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
40
+ # Perform authorization reversal
41
+ refund(money, identification_or_credit_card, options)
42
+ else
43
+ # Perform credit
44
+ request = build_credit_card_request(money, identification_or_credit_card, options)
45
+ commit(:credit_card_credit, request)
46
+ end
47
+ end
48
+
49
+ def refund(money, reference, options = {})
50
+ # Perform authorization reversal
51
+ request = build_refund_or_settle_request(money, reference, options)
52
+ commit(:credit_card_refund, request)
53
+ end
54
+
55
+ def void(identification, options = {})
56
+ requires!(options, :order_id)
57
+ original_transaction_id, _ = identification.split(";")
58
+ commit(:void_transaction, {:reference_number => format_reference_number(options[:order_id]), :transaction_id => original_transaction_id})
59
+ end
60
+
61
+ def voice_authorize(money, authorization_code, creditcard, options = {})
62
+ options[:authorization_number] = authorization_code
63
+ request = build_credit_card_request(money, creditcard, options)
64
+ commit(:credit_card_voice_authorize, request)
65
+ end
66
+
67
+ def force(money, authorization_code, creditcard, options = {})
68
+ options[:authorization_number] = authorization_code
69
+ request = build_credit_card_request(money, creditcard, options)
70
+ commit(:credit_card_capture, request)
71
+ end
72
+
73
+ def system_check
74
+ commit(:system_check, {})
75
+ end
76
+
77
+ private
78
+
79
+ def build_refund_or_settle_request(money, identification, options = {})
80
+ original_transaction_id, original_transaction_amount = identification.split(";")
81
+
82
+ requires!(options, :order_id)
83
+
84
+ {
85
+ :reference_number => format_reference_number(options[:order_id]),
86
+ :transaction_amount => amount(money),
87
+ :original_transaction_amount => original_transaction_amount,
88
+ :original_transaction_id => original_transaction_id,
89
+ :client_ip_address => options[:ip]
90
+ }
91
+ end
92
+
93
+ def build_credit_card_request(money, creditcard, options = {})
94
+ requires!(options, :order_id)
95
+
96
+ post = {
97
+ :reference_number => format_reference_number(options[:order_id]),
98
+ :authorization_number => options[:authorization_number],
99
+ :transaction_amount => amount(money),
100
+ :client_ip_address => options[:ip]
101
+
102
+ }
103
+ add_creditcard(post,creditcard)
104
+ add_address(post,options)
105
+ post
106
+ end
107
+
108
+ def format_reference_number(number)
109
+ number.to_s.slice(0,12)
110
+ end
111
+
112
+ def add_address(post,options)
113
+ if address = options[:billing_address] || options[:address]
114
+ if address[:address2]
115
+ post[:billing_address] = address[:address1].to_s << ' ' << address[:address2].to_s
116
+ else
117
+ post[:billing_address] = address[:address1].to_s
118
+ end
119
+ post[:billing_city] = address[:city].to_s
120
+ post[:billing_state] = address[:state].blank? ? 'n/a' : address[:state]
121
+ post[:billing_postal_code] = address[:zip].to_s
122
+ post[:billing_country] = address[:country].to_s
123
+ end
124
+
125
+ if address = options[:shipping_address]
126
+ if address[:address2]
127
+ post[:shipping_address] = address[:address1].to_s << ' ' << address[:address2].to_s
128
+ else
129
+ post[:shipping_address] = address[:address1].to_s
130
+ end
131
+ post[:shipping_city] = address[:city].to_s
132
+ post[:shipping_state] = address[:state].blank? ? 'n/a' : address[:state]
133
+ post[:shipping_postal_code] = address[:zip].to_s
134
+ post[:shipping_country] = address[:country].to_s
135
+ end
136
+ end
137
+
138
+ def add_creditcard(post, creditcard)
139
+ post[:billing_name] = creditcard.name if creditcard.name
140
+ post[:account_number] = creditcard.number
141
+ post[:card_verification_value] = creditcard.verification_value if creditcard.verification_value?
142
+ post[:expiration_month] = sprintf("%.2i", creditcard.month)
143
+ post[:expiration_year] = sprintf("%.4i", creditcard.year)[-2..-1]
144
+ end
145
+
146
+
147
+ def commit(action, parameters)
148
+ response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(action, parameters), 'Content-Type' => 'text/xml'))
149
+
150
+ Response.new(success?(response), message_from(response[:result_message]), response,
151
+ :test => test?,
152
+ :authorization => authorization_from(response, parameters),
153
+ :avs_result => { :code => response[:avs_response_code] },
154
+ :cvv_result => response[:cvv_response_code]
155
+ )
156
+ end
157
+
158
+ def success?(response)
159
+ response[:response_code] == '0'
160
+ end
161
+
162
+ def authorization_from(response, params)
163
+ [ response[:transaction_id], params[:transaction_amount] ].compact.join(';')
164
+ end
165
+
166
+ def parse(xml)
167
+ response = {}
168
+
169
+ xml = REXML::Document.new(xml)
170
+
171
+ xml.elements.each('//Reply//TransactionReply/*') do |node|
172
+
173
+ response[node.name.underscore.to_sym] = normalize(node.text)
174
+
175
+ end unless xml.root.nil?
176
+
177
+ response
178
+ end
179
+
180
+ def post_data(action, parameters = {})
181
+ xml = REXML::Document.new("<?xml version='1.0' encoding='UTF-8'?>")
182
+ root = xml.add_element("Request")
183
+ root.attributes["StoreID"] = options[:login]
184
+ root.attributes["StoreKey"] = options[:password]
185
+ root.attributes["ApplicationID"] = 'ot 1.0'
186
+ transaction = root.add_element(action.to_s.camelize)
187
+
188
+ actions[action].each do |key|
189
+ transaction.add_element(key).text = parameters[key.underscore.to_sym] unless parameters[key.underscore.to_sym].blank?
190
+ end
191
+
192
+ xml.to_s
193
+ end
194
+
195
+ def message_from(message)
196
+ return 'Unspecified error' if message.blank?
197
+ message.gsub(/[^\w]/, ' ').split.join(" ").capitalize
198
+ end
199
+
200
+ def actions
201
+ ACTIONS
202
+ end
203
+
204
+ CREDIT_CARD_FIELDS = %w(AuthorizationNumber ClientIpAddress BillingAddress BillingCity BillingState BillingPostalCode BillingCountry BillingName CardVerificationValue ExpirationMonth ExpirationYear ReferenceNumber TransactionAmount AccountNumber )
205
+
206
+ ACTIONS = {
207
+ :credit_card_authorize => CREDIT_CARD_FIELDS,
208
+ :credit_card_charge => CREDIT_CARD_FIELDS,
209
+ :credit_card_voice_authorize => CREDIT_CARD_FIELDS,
210
+ :credit_card_capture => CREDIT_CARD_FIELDS,
211
+ :credit_card_credit => CREDIT_CARD_FIELDS + ["OriginalTransactionAmount"],
212
+ :credit_card_refund => %w(ReferenceNumber TransactionAmount OriginalTransactionAmount OriginalTransactionID ClientIpAddress),
213
+ :void_transaction => %w(ReferenceNumber TransactionID),
214
+ :credit_card_settle => %w(ReferenceNumber TransactionAmount OriginalTransactionAmount OriginalTransactionID ClientIpAddress),
215
+ :system_check => %w(SystemCheck),
216
+ }
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,348 @@
1
+ require File.dirname(__FILE__) + '/viaklix'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # = Elavon Virtual Merchant Gateway
6
+ #
7
+ # == Example use:
8
+ #
9
+ # gateway = ActiveMerchant::Billing::ElavonGateway.new(
10
+ # :login => "my_virtual_merchant_id",
11
+ # :password => "my_virtual_merchant_pin",
12
+ # :user => "my_virtual_merchant_user_id" # optional
13
+ # )
14
+ #
15
+ # # set up credit card obj as in main ActiveMerchant example
16
+ # creditcard = ActiveMerchant::Billing::CreditCard.new(
17
+ # :type => 'visa',
18
+ # :number => '41111111111111111',
19
+ # :month => 10,
20
+ # :year => 2011,
21
+ # :first_name => 'Bob',
22
+ # :last_name => 'Bobsen'
23
+ # )
24
+ #
25
+ # # run request
26
+ # response = gateway.purchase(1000, creditcard) # authorize and capture 10 USD
27
+ #
28
+ # puts response.success? # Check whether the transaction was successful
29
+ # puts response.message # Retrieve the message returned by Elavon
30
+ # puts response.authorization # Retrieve the unique transaction ID returned by Elavon
31
+ #
32
+ class ElavonGateway < Gateway
33
+ class_attribute :test_url, :live_url, :delimiter, :actions
34
+
35
+ self.test_url = 'https://demo.myvirtualmerchant.com/VirtualMerchantDemo/process.do'
36
+ self.live_url = 'https://www.myvirtualmerchant.com/VirtualMerchant/process.do'
37
+
38
+ self.display_name = 'Elavon MyVirtualMerchant'
39
+ self.supported_countries = %w(US CA PR DE IE NO PL LU BE NL)
40
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
41
+ self.homepage_url = 'http://www.elavon.com/'
42
+
43
+ self.delimiter = "\n"
44
+ self.actions = {
45
+ :purchase => 'CCSALE',
46
+ :credit => 'CCCREDIT',
47
+ :refund => 'CCRETURN',
48
+ :authorize => 'CCAUTHONLY',
49
+ :capture => 'CCFORCE',
50
+ :void => 'CCDELETE',
51
+ :store => 'CCGETTOKEN',
52
+ :update => 'CCUPDATETOKEN',
53
+ }
54
+
55
+ # Initialize the Gateway
56
+ #
57
+ # The gateway requires that a valid login and password be passed
58
+ # in the +options+ hash.
59
+ #
60
+ # ==== Options
61
+ #
62
+ # * <tt>:login</tt> -- Merchant ID
63
+ # * <tt>:password</tt> -- PIN
64
+ # * <tt>:user</tt> -- Specify a subuser of the account (optional)
65
+ # * <tt>:test => +true+ or +false+</tt> -- Force test transactions
66
+ def initialize(options = {})
67
+ requires!(options, :login, :password)
68
+ super
69
+ end
70
+
71
+ # Make a purchase
72
+ def purchase(money, payment_method, options = {})
73
+ form = {}
74
+ add_salestax(form, options)
75
+ add_invoice(form, options)
76
+ if payment_method.is_a?(String)
77
+ add_token(form, payment_method)
78
+ else
79
+ add_creditcard(form, payment_method)
80
+ end
81
+ add_address(form, options)
82
+ add_customer_data(form, options)
83
+ add_test_mode(form, options)
84
+ commit(:purchase, money, form)
85
+ end
86
+
87
+ # Authorize a credit card for a given amount.
88
+ #
89
+ # ==== Parameters
90
+ # * <tt>money</tt> - The amount to be authorized as an Integer value in cents.
91
+ # * <tt>credit_card</tt> - The CreditCard details for the transaction.
92
+ # * <tt>options</tt>
93
+ # * <tt>:billing_address</tt> - The billing address for the cardholder.
94
+ def authorize(money, creditcard, options = {})
95
+ form = {}
96
+ add_salestax(form, options)
97
+ add_invoice(form, options)
98
+ add_creditcard(form, creditcard)
99
+ add_address(form, options)
100
+ add_customer_data(form, options)
101
+ add_test_mode(form, options)
102
+ commit(:authorize, money, form)
103
+ end
104
+
105
+ # Capture authorized funds from a credit card.
106
+ #
107
+ # ==== Parameters
108
+ # * <tt>money</tt> - The amount to be captured as an Integer value in cents.
109
+ # * <tt>authorization</tt> - The approval code returned from the initial authorization.
110
+ # * <tt>options</tt>
111
+ # * <tt>:credit_card</tt> - The CreditCard details from the initial transaction (required).
112
+ def capture(money, authorization, options = {})
113
+ requires!(options, :credit_card)
114
+
115
+ form = {}
116
+ add_salestax(form, options)
117
+ add_approval_code(form, authorization)
118
+ add_invoice(form, options)
119
+ add_creditcard(form, options[:credit_card])
120
+ add_customer_data(form, options)
121
+ add_test_mode(form, options)
122
+ commit(:capture, money, form)
123
+ end
124
+
125
+ # Refund a transaction.
126
+ #
127
+ # This transaction indicates to the gateway that
128
+ # money should flow from the merchant to the customer.
129
+ #
130
+ # ==== Parameters
131
+ #
132
+ # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
133
+ # * <tt>identification</tt> -- The ID of the original transaction against which the refund is being issued.
134
+ # * <tt>options</tt> -- A hash of parameters.
135
+ def refund(money, identification, options = {})
136
+ form = {}
137
+ add_txn_id(form, identification)
138
+ add_test_mode(form, options)
139
+ commit(:refund, money, form)
140
+ end
141
+
142
+ # Void a previous transaction
143
+ #
144
+ # ==== Parameters
145
+ #
146
+ # * <tt>authorization</tt> - The authorization returned from the previous request.
147
+ def void(identification, options = {})
148
+ form = {}
149
+ add_txn_id(form, identification)
150
+ add_test_mode(form, options)
151
+ commit(:void, nil, form)
152
+ end
153
+
154
+ # Make a credit to a card. Use the refund method if you'd like to credit using
155
+ # previous transaction
156
+ #
157
+ # ==== Parameters
158
+ # * <tt>money</tt> - The amount to be credited as an Integer value in cents.
159
+ # * <tt>creditcard</tt> - The credit card to be credited.
160
+ # * <tt>options</tt>
161
+ def credit(money, creditcard, options = {})
162
+ if creditcard.is_a?(String)
163
+ raise ArgumentError, "Reference credits are not supported. Please supply the original credit card or use the #refund method."
164
+ end
165
+
166
+ form = {}
167
+ add_invoice(form, options)
168
+ add_creditcard(form, creditcard)
169
+ add_address(form, options)
170
+ add_customer_data(form, options)
171
+ add_test_mode(form, options)
172
+ commit(:credit, money, form)
173
+ end
174
+
175
+ def verify(credit_card, options = {})
176
+ MultiResponse.run(:use_first_response) do |r|
177
+ r.process { authorize(100, credit_card, options) }
178
+ r.process(:ignore_result) { void(r.authorization, options) }
179
+ end
180
+ end
181
+
182
+ def store(creditcard, options = {})
183
+ form = {}
184
+ add_creditcard(form, creditcard)
185
+ add_address(form, options)
186
+ add_customer_data(form, options)
187
+ add_test_mode(form, options)
188
+ add_verification(form, options)
189
+ form[:add_token] = 'Y'
190
+ commit(:store, nil, form)
191
+ end
192
+
193
+ def update(token, creditcard, options = {})
194
+ form = {}
195
+ add_token(form, token)
196
+ add_creditcard(form, creditcard)
197
+ add_address(form, options)
198
+ add_customer_data(form, options)
199
+ add_test_mode(form, options)
200
+ commit(:update, nil, form)
201
+ end
202
+
203
+ private
204
+
205
+ def add_invoice(form,options)
206
+ form[:invoice_number] = (options[:order_id] || options[:invoice]).to_s.slice(0, 10)
207
+ form[:description] = options[:description].to_s.slice(0, 255)
208
+ end
209
+
210
+ def add_approval_code(form, authorization)
211
+ form[:approval_code] = authorization.split(';').first
212
+ end
213
+
214
+ def add_txn_id(form, authorization)
215
+ form[:txn_id] = authorization.split(';').last
216
+ end
217
+
218
+ def authorization_from(response)
219
+ [response['approval_code'], response['txn_id']].join(';')
220
+ end
221
+
222
+ def add_creditcard(form, creditcard)
223
+ form[:card_number] = creditcard.number
224
+ form[:exp_date] = expdate(creditcard)
225
+
226
+ if creditcard.verification_value?
227
+ add_verification_value(form, creditcard)
228
+ end
229
+
230
+ form[:first_name] = creditcard.first_name.to_s.slice(0, 20)
231
+ form[:last_name] = creditcard.last_name.to_s.slice(0, 30)
232
+ end
233
+
234
+ def add_token(form, token)
235
+ form[:token] = token
236
+ end
237
+
238
+ def add_verification_value(form, creditcard)
239
+ form[:cvv2cvc2] = creditcard.verification_value
240
+ form[:cvv2cvc2_indicator] = '1'
241
+ end
242
+
243
+ def add_customer_data(form, options)
244
+ form[:email] = options[:email].to_s.slice(0, 100) unless options[:email].blank?
245
+ form[:customer_code] = options[:customer].to_s.slice(0, 10) unless options[:customer].blank?
246
+ end
247
+
248
+ def add_salestax(form, options)
249
+ form[:salestax] = options[:tax] if options[:tax].present?
250
+ end
251
+
252
+ def add_address(form, options)
253
+ billing_address = options[:billing_address] || options[:address]
254
+
255
+ if billing_address
256
+ form[:avs_address] = billing_address[:address1].to_s.slice(0, 30)
257
+ form[:address2] = billing_address[:address2].to_s.slice(0, 30)
258
+ form[:avs_zip] = billing_address[:zip].to_s.gsub(/[^a-zA-Z0-9]/, '').slice(0, 9)
259
+ form[:city] = billing_address[:city].to_s.slice(0, 30)
260
+ form[:state] = billing_address[:state].to_s.slice(0, 10)
261
+ form[:company] = billing_address[:company].to_s.slice(0, 50)
262
+ form[:phone] = billing_address[:phone].to_s.slice(0, 20)
263
+ form[:country] = billing_address[:country].to_s.slice(0, 50)
264
+ end
265
+
266
+ if shipping_address = options[:shipping_address]
267
+ first_name, last_name = parse_first_and_last_name(shipping_address[:name])
268
+ form[:ship_to_first_name] = first_name.to_s.slice(0, 20)
269
+ form[:ship_to_last_name] = last_name.to_s.slice(0, 30)
270
+ form[:ship_to_address1] = shipping_address[:address1].to_s.slice(0, 30)
271
+ form[:ship_to_address2] = shipping_address[:address2].to_s.slice(0, 30)
272
+ form[:ship_to_city] = shipping_address[:city].to_s.slice(0, 30)
273
+ form[:ship_to_state] = shipping_address[:state].to_s.slice(0, 10)
274
+ form[:ship_to_company] = shipping_address[:company].to_s.slice(0, 50)
275
+ form[:ship_to_country] = shipping_address[:country].to_s.slice(0, 50)
276
+ form[:ship_to_zip] = shipping_address[:zip].to_s.slice(0, 10)
277
+ end
278
+ end
279
+
280
+ def add_verification(form, options)
281
+ form[:verify] = 'Y' if options[:verify]
282
+ end
283
+
284
+ def parse_first_and_last_name(value)
285
+ name = value.to_s.split(' ')
286
+
287
+ last_name = name.pop || ''
288
+ first_name = name.join(' ')
289
+ [ first_name, last_name ]
290
+ end
291
+
292
+ def add_test_mode(form, options)
293
+ form[:test_mode] = 'TRUE' if options[:test_mode]
294
+ end
295
+
296
+ def message_from(response)
297
+ success?(response) ? response['result_message'] : response['errorMessage']
298
+ end
299
+
300
+ def success?(response)
301
+ !response.has_key?('errorMessage')
302
+ end
303
+
304
+ def commit(action, money, parameters)
305
+ parameters[:amount] = amount(money)
306
+ parameters[:transaction_type] = self.actions[action]
307
+
308
+ response = parse( ssl_post(test? ? self.test_url : self.live_url, post_data(parameters)) )
309
+
310
+ Response.new(response['result'] == '0', message_from(response), response,
311
+ :test => @options[:test] || test?,
312
+ :authorization => authorization_from(response),
313
+ :avs_result => { :code => response['avs_response'] },
314
+ :cvv_result => response['cvv2_response']
315
+ )
316
+ end
317
+
318
+ def post_data(parameters)
319
+ result = preamble
320
+ result.merge!(parameters)
321
+ result.collect { |key, value| "ssl_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
322
+ end
323
+
324
+ def preamble
325
+ result = {
326
+ 'merchant_id' => @options[:login],
327
+ 'pin' => @options[:password],
328
+ 'show_form' => 'false',
329
+ 'result_format' => 'ASCII'
330
+ }
331
+
332
+ result['user_id'] = @options[:user] unless @options[:user].blank?
333
+ result
334
+ end
335
+
336
+ def parse(msg)
337
+ resp = {}
338
+ msg.split(self.delimiter).collect{|li|
339
+ key, value = li.split("=")
340
+ resp[key.to_s.strip.gsub(/^ssl_/, '')] = value.to_s.strip
341
+ }
342
+ resp
343
+ end
344
+
345
+ end
346
+ end
347
+ end
348
+