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,252 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class SecureNetGateway < Gateway
4
+
5
+ API_VERSION = "4.0"
6
+
7
+ TRANSACTIONS = {
8
+ :auth_only => "0000",
9
+ :auth_capture => "0100",
10
+ :prior_auth_capture => "0200",
11
+ :void => "0400",
12
+ :credit => "0500"
13
+ }
14
+
15
+ XML_ATTRIBUTES = {
16
+ 'xmlns' => "http://gateway.securenet.com/API/Contracts",
17
+ 'xmlns:i' => "http://www.w3.org/2001/XMLSchema-instance"
18
+ }
19
+ NIL_ATTRIBUTE = { 'i:nil' => "true" }
20
+
21
+ self.supported_countries = ['US']
22
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
23
+ self.homepage_url = 'http://www.securenet.com/'
24
+ self.display_name = 'SecureNet'
25
+
26
+ self.test_url = 'https://certify.securenet.com/API/gateway.svc/webHttp/ProcessTransaction'
27
+ self.live_url = 'https://gateway.securenet.com/api/Gateway.svc/webHttp/ProcessTransaction'
28
+
29
+ APPROVED, DECLINED = 1, 2
30
+
31
+ CARD_CODE_ERRORS = %w( N S )
32
+ AVS_ERRORS = %w( A E N R W Z )
33
+
34
+ def initialize(options = {})
35
+ requires!(options, :login, :password)
36
+ super
37
+ end
38
+
39
+ def authorize(money, creditcard, options = {})
40
+ commit(build_sale_or_authorization(creditcard, options, :auth_only, money))
41
+ end
42
+
43
+ def purchase(money, creditcard, options = {})
44
+ commit(build_sale_or_authorization(creditcard, options, :auth_capture, money))
45
+ end
46
+
47
+ def capture(money, authorization, options = {})
48
+ commit(build_capture_refund_void(authorization, options, :prior_auth_capture, money))
49
+ end
50
+
51
+ def void(authorization, options = {})
52
+ commit(build_capture_refund_void(authorization, options, :void))
53
+ end
54
+
55
+ def refund(money, authorization, options = {})
56
+ commit(build_capture_refund_void(authorization, options, :credit, money))
57
+ end
58
+
59
+ def credit(money, authorization, options = {})
60
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
61
+ refund(money, authorization, options)
62
+ end
63
+
64
+
65
+ private
66
+ def commit(request)
67
+ xml = build_request(request)
68
+ url = test? ? self.test_url : self.live_url
69
+ data = ssl_post(url, xml, "Content-Type" => "text/xml")
70
+ response = parse(data)
71
+
72
+ Response.new(success?(response), message_from(response), response,
73
+ :test => test?,
74
+ :authorization => build_authorization(response),
75
+ :avs_result => { :code => response[:avs_result_code] },
76
+ :cvv_result => response[:card_code_response_code]
77
+ )
78
+ end
79
+
80
+ def build_request(request)
81
+ xml = Builder::XmlMarkup.new
82
+
83
+ xml.instruct!
84
+ xml.tag!("TRANSACTION", XML_ATTRIBUTES) do
85
+ xml << request
86
+ end
87
+
88
+ xml.target!
89
+ end
90
+
91
+ def build_sale_or_authorization(creditcard, options, action, money)
92
+ xml = Builder::XmlMarkup.new
93
+
94
+ xml.tag! 'AMOUNT', amount(money)
95
+ add_credit_card(xml, creditcard)
96
+ add_params_in_required_order(xml, action, options)
97
+ add_address(xml, creditcard, options)
98
+ add_more_required_params(xml, options)
99
+
100
+ xml.target!
101
+ end
102
+
103
+ def build_capture_refund_void(authorization, options, action, money = nil)
104
+ xml = Builder::XmlMarkup.new
105
+
106
+ transaction_id, amount_in_ref, last_four = split_authorization(authorization)
107
+
108
+ xml.tag! 'AMOUNT', amount(money) || amount_in_ref
109
+ xml.tag!("CARD") do
110
+ xml.tag! 'CARDNUMBER', last_four
111
+ end
112
+
113
+ add_params_in_required_order(xml, action, options)
114
+ xml.tag! 'REF_TRANSID', transaction_id
115
+ add_more_required_params(xml, options)
116
+
117
+ xml.target!
118
+ end
119
+
120
+ def add_credit_card(xml, creditcard)
121
+ xml.tag!("CARD") do
122
+ xml.tag! 'CARDCODE', creditcard.verification_value if creditcard.verification_value?
123
+ xml.tag! 'CARDNUMBER', creditcard.number
124
+ xml.tag! 'EXPDATE', expdate(creditcard)
125
+ end
126
+ end
127
+
128
+ def add_customer_data(xml, options)
129
+ if options.has_key? :customer
130
+ xml.tag! 'CUSTOMERID', options[:customer]
131
+ end
132
+
133
+ if options.has_key? :ip
134
+ xml.tag! 'CUSTOMERIP', options[:ip]
135
+ end
136
+ end
137
+
138
+ def add_address(xml, creditcard, options)
139
+
140
+ if address = options[:billing_address] || options[:address]
141
+ xml.tag!("CUSTOMER_BILL") do
142
+ xml.tag! 'ADDRESS', address[:address1].to_s
143
+ xml.tag! 'CITY', address[:city].to_s
144
+ xml.tag! 'COMPANY', address[:company].to_s
145
+ xml.tag! 'COUNTRY', address[:country].to_s
146
+ if options.has_key? :email
147
+ xml.tag! 'EMAIL', options[:email]
148
+ xml.tag! 'EMAILRECEIPT', 'FALSE'
149
+ end
150
+ xml.tag! 'FIRSTNAME', creditcard.first_name
151
+ xml.tag! 'LASTNAME', creditcard.last_name
152
+ xml.tag! 'PHONE', address[:phone].to_s
153
+ xml.tag! 'STATE', address[:state].blank? ? 'n/a' : address[:state]
154
+ xml.tag! 'ZIP', address[:zip].to_s
155
+ end
156
+ end
157
+
158
+ if address = options[:shipping_address]
159
+ xml.tag!("CUSTOMER_SHIP") do
160
+ xml.tag! 'ADDRESS', address[:address1].to_s
161
+ xml.tag! 'CITY', address[:city].to_s
162
+ xml.tag! 'COMPANY', address[:company].to_s
163
+ xml.tag! 'COUNTRY', address[:country].to_s
164
+ xml.tag! 'FIRSTNAME', address[:first_name].to_s
165
+ xml.tag! 'LASTNAME', address[:last_name].to_s
166
+ xml.tag! 'STATE', address[:state].blank? ? 'n/a' : address[:state]
167
+ xml.tag! 'ZIP', address[:zip].to_s
168
+ end
169
+ else
170
+ xml.tag!('CUSTOMER_SHIP', NIL_ATTRIBUTE) do
171
+ end
172
+ end
173
+
174
+ end
175
+
176
+ def add_merchant_key(xml, options)
177
+ xml.tag!("MERCHANT_KEY") do
178
+ xml.tag! 'GROUPID', 0
179
+ xml.tag! 'SECUREKEY', @options[:password]
180
+ xml.tag! 'SECURENETID', @options[:login]
181
+ end
182
+ end
183
+
184
+ # SecureNet requires some of the xml params to be in a certain order. http://cl.ly/image/3K260E0p0a0n/content.png
185
+ def add_params_in_required_order(xml, action, options)
186
+ xml.tag! 'CODE', TRANSACTIONS[action]
187
+ add_customer_data(xml, options)
188
+ xml.tag! 'DCI', 0 # No duplicate checking will be done, except for ORDERID
189
+ xml.tag! 'INSTALLMENT_SEQUENCENUM', 1
190
+ xml.tag! 'INVOICEDESC', options[:invoice_description] if options[:invoice_description]
191
+ xml.tag! 'INVOICENUM', options[:invoice_number] if options[:invoice_number]
192
+ add_merchant_key(xml, options)
193
+ xml.tag! 'METHOD', 'CC'
194
+ xml.tag! 'NOTE', options[:description] if options[:description]
195
+ xml.tag! 'ORDERID', options[:order_id]
196
+ xml.tag! 'OVERRIDE_FROM', 0 # Docs say not required, but doesn't work without it
197
+ end
198
+
199
+ def add_more_required_params(xml, options)
200
+ xml.tag! 'RETAIL_LANENUM', '0'
201
+ xml.tag! 'TEST', 'TRUE' if test?
202
+ xml.tag! 'TOTAL_INSTALLMENTCOUNT', 0
203
+ xml.tag! 'TRANSACTION_SERVICE', 0
204
+ end
205
+
206
+ def success?(response)
207
+ response[:response_code].to_i == APPROVED
208
+ end
209
+
210
+ def message_from(response)
211
+ if response[:response_code].to_i == DECLINED
212
+ return CVVResult.messages[ response[:card_code_response_code] ] if CARD_CODE_ERRORS.include?(response[:card_code_response_code])
213
+ return AVSResult.messages[ response[:avs_result_code] ] if AVS_ERRORS.include?(response[:avs_result_code])
214
+ end
215
+
216
+ return response[:response_reason_text].nil? ? '' : response[:response_reason_text][0..-1]
217
+ end
218
+
219
+ def parse(xml)
220
+ response = {}
221
+ xml = REXML::Document.new(xml)
222
+ root = REXML::XPath.first(xml, "//GATEWAYRESPONSE")
223
+ if root
224
+ root.elements.to_a.each do |node|
225
+ recurring_parse_element(response, node)
226
+ end
227
+ end
228
+
229
+ response
230
+ end
231
+
232
+ def recurring_parse_element(response, node)
233
+ if node.has_elements?
234
+ node.elements.each{|e| recurring_parse_element(response, e) }
235
+ else
236
+ response[node.name.underscore.to_sym] = node.text
237
+ end
238
+ end
239
+
240
+ def split_authorization(authorization)
241
+ transaction_id, amount, last_four = authorization.split("|")
242
+ [transaction_id, amount, last_four]
243
+ end
244
+
245
+ def build_authorization(response)
246
+ [response[:transactionid], response[:transactionamount], response[:last4_digits]].join("|")
247
+ end
248
+
249
+ end
250
+ end
251
+ end
252
+
@@ -0,0 +1,201 @@
1
+ require File.dirname(__FILE__) + '/authorize_net'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class SecurePayGateway < Gateway
6
+ API_VERSION = '3.1'
7
+
8
+ self.live_url = self.test_url = 'https://www.securepay.com/AuthSpayAdapter/process.aspx'
9
+
10
+ class_attribute :duplicate_window
11
+
12
+ APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
13
+
14
+ RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT, AUTHORIZATION_CODE = 0, 2, 3, 4
15
+ AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE, CARDHOLDER_AUTH_CODE = 5, 6, 38, 39
16
+
17
+ self.default_currency = 'USD'
18
+
19
+ self.supported_countries = %w(US CA GB AU)
20
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
21
+ self.homepage_url = 'http://www.securepay.com/'
22
+ self.display_name = 'SecurePay'
23
+
24
+ CARD_CODE_ERRORS = %w( N S )
25
+ AVS_ERRORS = %w( A E N R W Z )
26
+ AVS_REASON_CODES = %w(27 45)
27
+ TRANSACTION_ALREADY_ACTIONED = %w(310 311)
28
+
29
+ def initialize(options = {})
30
+ requires!(options, :login, :password)
31
+ super
32
+ end
33
+
34
+ def purchase(money, paysource, options = {})
35
+ post = {}
36
+ add_currency_code(post, money, options)
37
+ add_invoice(post, options)
38
+ add_payment_source(post, paysource, options)
39
+ add_address(post, options)
40
+ add_customer_data(post, options)
41
+ add_duplicate_window(post)
42
+
43
+ commit('AUTH_CAPTURE', money, post)
44
+ end
45
+
46
+ private
47
+
48
+ def commit(action, money, parameters)
49
+ parameters[:amount] = amount(money) unless action == 'VOID'
50
+
51
+ url = (test? ? self.test_url : self.live_url)
52
+ data = ssl_post(url, post_data(action, parameters))
53
+
54
+ response = parse(data)
55
+ response[:action] = action
56
+
57
+ message = message_from(response)
58
+
59
+ Response.new(success?(response), message, response,
60
+ :test => test?,
61
+ :authorization => response[:transaction_id],
62
+ :fraud_review => fraud_review?(response),
63
+ :avs_result => { :code => response[:avs_result_code] },
64
+ :cvv_result => response[:card_code]
65
+ )
66
+ end
67
+
68
+ def success?(response)
69
+ response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
70
+ end
71
+
72
+ def fraud_review?(response)
73
+ response[:response_code] == FRAUD_REVIEW
74
+ end
75
+
76
+ def parse(body)
77
+ fields = split(body)
78
+
79
+ results = {
80
+ :response_code => fields[RESPONSE_CODE].to_i,
81
+ :response_reason_code => fields[RESPONSE_REASON_CODE],
82
+ :response_reason_text => fields[RESPONSE_REASON_TEXT],
83
+ :avs_result_code => fields[AVS_RESULT_CODE],
84
+ :transaction_id => fields[TRANSACTION_ID],
85
+ :card_code => fields[CARD_CODE_RESPONSE_CODE],
86
+ :authorization_code => fields[AUTHORIZATION_CODE],
87
+ :cardholder_authentication_code => fields[CARDHOLDER_AUTH_CODE]
88
+ }
89
+ results
90
+ end
91
+
92
+ def post_data(action, parameters = {})
93
+ post = {}
94
+
95
+ post[:version] = API_VERSION
96
+ post[:login] = @options[:login]
97
+ post[:tran_key] = @options[:password]
98
+ post[:relay_response] = "FALSE"
99
+ post[:type] = action
100
+ post[:delim_data] = "TRUE"
101
+ post[:delim_char] = ","
102
+ post[:encap_char] = "$"
103
+ post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
104
+
105
+ request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
106
+ request
107
+ end
108
+
109
+ def add_currency_code(post, money, options)
110
+ post[:currency_code] = options[:currency] || currency(money)
111
+ end
112
+
113
+ def add_invoice(post, options)
114
+ post[:invoice_num] = options[:order_id]
115
+ post[:description] = options[:description]
116
+ end
117
+
118
+ def add_creditcard(post, creditcard, options={})
119
+ post[:card_num] = creditcard.number
120
+ post[:card_code] = creditcard.verification_value if creditcard.verification_value?
121
+ post[:exp_date] = expdate(creditcard)
122
+ post[:first_name] = creditcard.first_name
123
+ post[:last_name] = creditcard.last_name
124
+ end
125
+
126
+ def add_payment_source(params, source, options={})
127
+ add_creditcard(params, source, options)
128
+ end
129
+
130
+ def add_customer_data(post, options)
131
+ if options.has_key? :email
132
+ post[:email] = options[:email]
133
+ post[:email_customer] = false
134
+ end
135
+
136
+ if options.has_key? :customer
137
+ post[:cust_id] = options[:customer] if Float(options[:customer]) rescue nil
138
+ end
139
+
140
+ if options.has_key? :ip
141
+ post[:customer_ip] = options[:ip]
142
+ end
143
+
144
+ if options.has_key? :cardholder_authentication_value
145
+ post[:cardholder_authentication_value] = options[:cardholder_authentication_value]
146
+ end
147
+
148
+ if options.has_key? :authentication_indicator
149
+ post[:authentication_indicator] = options[:authentication_indicator]
150
+ end
151
+ end
152
+
153
+ # x_duplicate_window won't be sent by default, because sending it changes the response.
154
+ # "If this field is present in the request with or without a value, an enhanced duplicate transaction response will be sent."
155
+ # (as of 2008-12-30) http://www.authorize.net/support/AIM_guide_SCC.pdf
156
+ def add_duplicate_window(post)
157
+ post[:duplicate_window] = duplicate_window if duplicate_window
158
+ end
159
+
160
+ def add_address(post, options)
161
+ if address = options[:billing_address] || options[:address]
162
+ post[:address] = address[:address1].to_s
163
+ post[:company] = address[:company].to_s
164
+ post[:phone] = address[:phone].to_s
165
+ post[:zip] = address[:zip].to_s
166
+ post[:city] = address[:city].to_s
167
+ post[:country] = address[:country].to_s
168
+ post[:state] = address[:state].blank? ? 'n/a' : address[:state]
169
+ end
170
+
171
+ if address = options[:shipping_address]
172
+ post[:ship_to_first_name] = address[:first_name].to_s
173
+ post[:ship_to_last_name] = address[:last_name].to_s
174
+ post[:ship_to_address] = address[:address1].to_s
175
+ post[:ship_to_company] = address[:company].to_s
176
+ post[:ship_to_phone] = address[:phone].to_s
177
+ post[:ship_to_zip] = address[:zip].to_s
178
+ post[:ship_to_city] = address[:city].to_s
179
+ post[:ship_to_country] = address[:country].to_s
180
+ post[:ship_to_state] = address[:state].blank? ? 'n/a' : address[:state]
181
+ end
182
+ end
183
+
184
+ def message_from(results)
185
+ if results[:response_code] == DECLINED
186
+ return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
187
+ if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
188
+ return AVSResult.messages[ results[:avs_result_code] ]
189
+ end
190
+ end
191
+
192
+ (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
193
+ end
194
+
195
+ def split(response)
196
+ response.split(',')
197
+ end
198
+ end
199
+ end
200
+ end
201
+