gonow-activemerchant 1.15.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 (189) hide show
  1. data/CHANGELOG +690 -0
  2. data/CONTRIBUTORS +237 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +165 -0
  5. data/gem-public_cert.pem +20 -0
  6. data/lib/active_merchant.rb +47 -0
  7. data/lib/active_merchant/billing.rb +9 -0
  8. data/lib/active_merchant/billing/avs_result.rb +98 -0
  9. data/lib/active_merchant/billing/base.rb +57 -0
  10. data/lib/active_merchant/billing/check.rb +68 -0
  11. data/lib/active_merchant/billing/credit_card.rb +178 -0
  12. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  13. data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
  14. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  15. data/lib/active_merchant/billing/expiry_date.rb +34 -0
  16. data/lib/active_merchant/billing/gateway.rb +170 -0
  17. data/lib/active_merchant/billing/gateways.rb +18 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net.rb +664 -0
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
  20. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  21. data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
  22. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -0
  23. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  24. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  25. data/lib/active_merchant/billing/gateways/bogus.rb +132 -0
  26. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  27. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  28. data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
  29. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
  30. data/lib/active_merchant/billing/gateways/braspag.rb +188 -0
  31. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
  32. data/lib/active_merchant/billing/gateways/cyber_source.rb +430 -0
  33. data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
  34. data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
  35. data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
  36. data/lib/active_merchant/billing/gateways/epay.rb +268 -0
  37. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  39. data/lib/active_merchant/billing/gateways/exact.rb +222 -0
  40. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  41. data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
  42. data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
  43. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  44. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  45. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  46. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  47. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  48. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  49. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  50. data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
  51. data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
  52. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +156 -0
  53. data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
  54. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  55. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
  56. data/lib/active_merchant/billing/gateways/moneris.rb +209 -0
  57. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  58. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  59. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  60. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  61. data/lib/active_merchant/billing/gateways/ogone.rb +292 -0
  62. data/lib/active_merchant/billing/gateways/orbital.rb +321 -0
  63. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  64. data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
  65. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  66. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  67. data/lib/active_merchant/billing/gateways/payflow.rb +253 -0
  68. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
  69. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  70. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  71. data/lib/active_merchant/billing/gateways/payflow_express.rb +222 -0
  72. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  73. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  74. data/lib/active_merchant/billing/gateways/payment_express.rb +235 -0
  75. data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
  76. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +351 -0
  77. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
  78. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  79. data/lib/active_merchant/billing/gateways/paypal_express.rb +177 -0
  80. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  81. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  82. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  83. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  84. data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
  85. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  86. data/lib/active_merchant/billing/gateways/quickpay.rb +218 -0
  87. data/lib/active_merchant/billing/gateways/realex.rb +311 -0
  88. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  89. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  90. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  91. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  92. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  93. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  94. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  95. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  96. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
  97. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  98. data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
  99. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  100. data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
  101. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  102. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  103. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  104. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  105. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  106. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  107. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  108. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  109. data/lib/active_merchant/billing/integrations.rb +17 -0
  110. data/lib/active_merchant/billing/integrations/action_view_helper.rb +68 -0
  111. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  112. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  113. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  114. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  115. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  116. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  117. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  118. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  119. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  120. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  121. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  122. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  123. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  124. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  125. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  126. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  127. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  128. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  129. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  130. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  131. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  132. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  133. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  134. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  135. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  136. data/lib/active_merchant/billing/integrations/helper.rb +96 -0
  137. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  138. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  139. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  140. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  141. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  142. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  143. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  144. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  145. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  146. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  147. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  148. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  149. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  150. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  151. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  152. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  153. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  154. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  155. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  156. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  157. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  158. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  159. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  160. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  161. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  162. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  163. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  164. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  165. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  166. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  167. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  168. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  169. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  170. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  171. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  172. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  173. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  174. data/lib/active_merchant/billing/response.rb +32 -0
  175. data/lib/active_merchant/common.rb +14 -0
  176. data/lib/active_merchant/common/connection.rb +177 -0
  177. data/lib/active_merchant/common/country.rb +328 -0
  178. data/lib/active_merchant/common/error.rb +26 -0
  179. data/lib/active_merchant/common/post_data.rb +24 -0
  180. data/lib/active_merchant/common/posts_data.rb +63 -0
  181. data/lib/active_merchant/common/requires_parameters.rb +16 -0
  182. data/lib/active_merchant/common/utils.rb +22 -0
  183. data/lib/active_merchant/common/validateable.rb +81 -0
  184. data/lib/active_merchant/version.rb +3 -0
  185. data/lib/activemerchant.rb +1 -0
  186. data/lib/certs/cacert.pem +7815 -0
  187. data/lib/support/gateway_support.rb +58 -0
  188. data/lib/support/outbound_hosts.rb +25 -0
  189. metadata +276 -0
@@ -0,0 +1,295 @@
1
+ require 'securerandom'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class QbmsGateway < Gateway
6
+ API_VERSION = '4.0'
7
+
8
+ class_attribute :test_url, :live_url
9
+
10
+ self.test_url = "https://webmerchantaccount.ptc.quickbooks.com/j/AppGateway"
11
+ self.live_url = "https://webmerchantaccount.quickbooks.com/j/AppGateway"
12
+
13
+ self.homepage_url = 'http://payments.intuit.com/'
14
+ self.display_name = 'QuickBooks Merchant Services'
15
+ self.default_currency = 'USD'
16
+ self.supported_cardtypes = [ :visa, :master, :discover, :american_express, :diners_club, :jcb ]
17
+ self.supported_countries = [ 'US' ]
18
+
19
+ TYPES = {
20
+ :authorize => 'CustomerCreditCardAuth',
21
+ :capture => 'CustomerCreditCardCapture',
22
+ :purchase => 'CustomerCreditCardCharge',
23
+ :refund => 'CustomerCreditCardTxnVoidOrRefund',
24
+ :void => 'CustomerCreditCardTxnVoid',
25
+ :query => 'MerchantAccountQuery',
26
+ }
27
+
28
+ # Creates a new QbmsGateway
29
+ #
30
+ # The gateway requires that a valid app id, app login, and ticket be passed
31
+ # in the +options+ hash.
32
+ #
33
+ # ==== Options
34
+ #
35
+ # * <tt>:login</tt> -- The App Login (REQUIRED)
36
+ # * <tt>:ticket</tt> -- The Connection Ticket. (REQUIRED)
37
+ # * <tt>:pem</tt> -- The PEM-encoded SSL client key and certificate. (REQUIRED)
38
+ # * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
39
+ # Otherwise, perform transactions against the production server.
40
+ #
41
+ def initialize(options = {})
42
+ requires!(options, :login, :ticket)
43
+ test_mode = options[:test] || false
44
+ @options = options
45
+ super
46
+ end
47
+
48
+ # Performs an authorization, which reserves the funds on the customer's credit card, but does not
49
+ # charge the card.
50
+ #
51
+ # ==== Parameters
52
+ #
53
+ # * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
54
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
55
+ # * <tt>options</tt> -- A hash of optional parameters.
56
+ #
57
+ def authorize(money, creditcard, options = {})
58
+ commit(:authorize, money, options.merge(:credit_card => creditcard))
59
+ end
60
+
61
+ # Perform a purchase, which is essentially an authorization and capture in a single operation.
62
+ #
63
+ # ==== Parameters
64
+ #
65
+ # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
66
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
67
+ # * <tt>options</tt> -- A hash of optional parameters.
68
+ #
69
+ def purchase(money, creditcard, options = {})
70
+ commit(:purchase, money, options.merge(:credit_card => creditcard))
71
+ end
72
+
73
+ # Captures the funds from an authorized transaction.
74
+ #
75
+ # ==== Parameters
76
+ #
77
+ # * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
78
+ # * <tt>authorization</tt> -- The authorization returned from the previous authorize request.
79
+ #
80
+ def capture(money, authorization, options = {})
81
+ commit(:capture, money, options.merge(:transaction_id => authorization))
82
+ end
83
+
84
+ # Void a previous transaction
85
+ #
86
+ # ==== Parameters
87
+ #
88
+ # * <tt>authorization</tt> - The authorization returned from the previous authorize request.
89
+ #
90
+ def void(authorization, options = {})
91
+ commit(:void, nil, options.merge(:transaction_id => authorization))
92
+ end
93
+
94
+ # Credit an account.
95
+ #
96
+ # This transaction is also referred to as a Refund and indicates to the gateway that
97
+ # money should flow from the merchant to the customer.
98
+ #
99
+ # ==== Parameters
100
+ #
101
+ # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
102
+ # * <tt>identification</tt> -- The ID of the original transaction against which the credit is being issued.
103
+ # * <tt>options</tt> -- A hash of parameters.
104
+ #
105
+ #
106
+ def credit(money, identification, options = {})
107
+ deprecated CREDIT_DEPRECATION_MESSAGE
108
+ refund(money, identification, options = {})
109
+ end
110
+
111
+ def refund(money, identification, options = {})
112
+ commit(:refund, money, options.merge(:transaction_id => identification))
113
+ end
114
+
115
+ # Query the merchant account status
116
+ def query
117
+ commit(:query, nil, {})
118
+ end
119
+
120
+ private
121
+
122
+ def hosted?
123
+ @options[:pem]
124
+ end
125
+
126
+ def commit(action, money, parameters)
127
+ url = test? ? self.test_url : self.live_url
128
+
129
+ type = TYPES[action]
130
+ parameters[:trans_request_id] ||= SecureRandom.hex(10)
131
+
132
+ req = build_request(type, money, parameters)
133
+ data = ssl_post(url, req, "Content-Type" => "application/x-qbmsxml")
134
+ response = parse(type, data)
135
+ message = (response[:status_message] || '').strip
136
+
137
+ Response.new(success?(response), message, response,
138
+ :test => test?,
139
+ :authorization => response[:credit_card_trans_id],
140
+ :fraud_review => fraud_review?(response),
141
+ :avs_result => { :code => avs_result(response) },
142
+ :cvv_result => cvv_result(response)
143
+ )
144
+ end
145
+
146
+ def success?(response)
147
+ response[:status_code] == 0
148
+ end
149
+
150
+ def fraud_review?(response)
151
+ [10100, 10101].member? response[:status_code]
152
+ end
153
+
154
+ def parse(type, body)
155
+ xml = REXML::Document.new(body)
156
+
157
+ signon = REXML::XPath.first(xml, "//SignonMsgsRs/#{hosted? ? 'SignonAppCertRs' : 'SignonDesktopRs'}")
158
+ status_code = signon.attributes["statusCode"].to_i
159
+
160
+ if status_code != 0
161
+ return {
162
+ :status_code => status_code,
163
+ :status_message => signon.attributes["statusMessage"],
164
+ }
165
+ end
166
+
167
+ response = REXML::XPath.first(xml, "//QBMSXMLMsgsRs/#{type}Rs")
168
+
169
+ results = {
170
+ :status_code => response.attributes["statusCode"].to_i,
171
+ :status_message => response.attributes["statusMessage"],
172
+ }
173
+
174
+ response.elements.each do |e|
175
+ name = e.name.underscore.to_sym
176
+ value = e.text()
177
+
178
+ if old_value = results[name]
179
+ results[name] = [old_value] if !old_value.kind_of?(Array)
180
+ results[name] << value
181
+ else
182
+ results[name] = value
183
+ end
184
+ end
185
+
186
+ results
187
+ end
188
+
189
+ def build_request(type, money, parameters = {})
190
+ xml = Builder::XmlMarkup.new(:indent => 0)
191
+
192
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'utf-8')
193
+ xml.instruct!(:qbmsxml, :version => API_VERSION)
194
+
195
+ xml.tag!("QBMSXML") do
196
+ xml.tag!("SignonMsgsRq") do
197
+ xml.tag!(hosted? ? "SignonAppCertRq" : "SignonDesktopRq") do
198
+ xml.tag!("ClientDateTime", Time.now.xmlschema)
199
+ xml.tag!("ApplicationLogin", @options[:login])
200
+ xml.tag!("ConnectionTicket", @options[:ticket])
201
+ end
202
+ end
203
+
204
+ xml.tag!("QBMSXMLMsgsRq") do
205
+ xml.tag!("#{type}Rq") do
206
+ method("build_#{type}").call(xml, money, parameters)
207
+ end
208
+ end
209
+ end
210
+
211
+ xml.target!
212
+ end
213
+
214
+ def build_CustomerCreditCardAuth(xml, money, parameters)
215
+ cc = parameters[:credit_card]
216
+ name = "#{cc.first_name} #{cc.last_name}"[0...30]
217
+
218
+ xml.tag!("TransRequestID", parameters[:trans_request_id])
219
+ xml.tag!("CreditCardNumber", cc.number)
220
+ xml.tag!("ExpirationMonth", cc.month)
221
+ xml.tag!("ExpirationYear", cc.year)
222
+ xml.tag!("IsECommerce", "true")
223
+ xml.tag!("Amount", amount(money))
224
+ xml.tag!("NameOnCard", name)
225
+ add_address(xml, parameters)
226
+ xml.tag!("CardSecurityCode", cc.verification_value) if cc.verification_value?
227
+ end
228
+
229
+ def build_CustomerCreditCardCapture(xml, money, parameters)
230
+ xml.tag!("TransRequestID", parameters[:trans_request_id])
231
+ xml.tag!("CreditCardTransID", parameters[:transaction_id])
232
+ xml.tag!("Amount", amount(money))
233
+ end
234
+
235
+ def build_CustomerCreditCardCharge(xml, money, parameters)
236
+ cc = parameters[:credit_card]
237
+ name = "#{cc.first_name} #{cc.last_name}"[0...30]
238
+
239
+ xml.tag!("TransRequestID", parameters[:trans_request_id])
240
+ xml.tag!("CreditCardNumber", cc.number)
241
+ xml.tag!("ExpirationMonth", cc.month)
242
+ xml.tag!("ExpirationYear", cc.year)
243
+ xml.tag!("IsECommerce", "true")
244
+ xml.tag!("Amount", amount(money))
245
+ xml.tag!("NameOnCard", name)
246
+ add_address(xml, parameters)
247
+ xml.tag!("CardSecurityCode", cc.verification_value) if cc.verification_value?
248
+ end
249
+
250
+ def build_CustomerCreditCardTxnVoidOrRefund(xml, money, parameters)
251
+ xml.tag!("TransRequestID", parameters[:trans_request_id])
252
+ xml.tag!("CreditCardTransID", parameters[:transaction_id])
253
+ xml.tag!("Amount", amount(money))
254
+ end
255
+
256
+ def build_CustomerCreditCardTxnVoid(xml, money, parameters)
257
+ xml.tag!("TransRequestID", parameters[:trans_request_id])
258
+ xml.tag!("CreditCardTransID", parameters[:transaction_id])
259
+ end
260
+
261
+ # Called reflectively by build_request
262
+ def build_MerchantAccountQuery(xml, money, parameters)
263
+ end
264
+
265
+ def add_address(xml, parameters)
266
+ if address = parameters[:billing_address] || parameters[:address]
267
+ xml.tag!("CreditCardAddress", address[:address1][0...30])
268
+ xml.tag!("CreditCardPostalCode", address[:zip][0...9])
269
+ end
270
+ end
271
+
272
+ def cvv_result(response)
273
+ case response[:card_security_code_match]
274
+ when "Pass" then 'M'
275
+ when "Fail" then 'N'
276
+ when "NotAvailable" then 'P'
277
+ end
278
+ end
279
+
280
+ def avs_result(response)
281
+ case "#{response[:avs_street]}|#{response[:avs_zip]}"
282
+ when "Pass|Pass" then "D"
283
+ when "Pass|Fail" then "A"
284
+ when "Pass|NotAvailable" then "B"
285
+ when "Fail|Pass" then "Z"
286
+ when "Fail|Fail" then "C"
287
+ when "Fail|NotAvailable" then "N"
288
+ when "NotAvailable|Pass" then "P"
289
+ when "NotAvailable|Fail" then "N"
290
+ when "NotAvailable|NotAvailable" then "U"
291
+ end
292
+ end
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,282 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # ActiveMerchant Implementation for Quantum Gateway XML Requester Service
4
+ # Based on API Doc from 8/6/2009
5
+ #
6
+ # Important Notes
7
+ # * Support is included for a customer id via the :customer option, invoice number via :invoice option, invoice description via :merchant option and memo via :description option
8
+ # * You can force email of receipt with :email_receipt => true
9
+ # * You can force email of merchant receipt with :merchant_receipt => true
10
+ # * You can exclude CVV with :ignore_cvv => true
11
+ # * All transactions use dollar values.
12
+ class QuantumGateway < Gateway
13
+ LIVE_URL = 'https://secure.quantumgateway.com/cgi/xml_requester.php'
14
+
15
+ # visa, master, american_express, discover
16
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
17
+ self.supported_countries = ['US']
18
+ self.default_currency = 'USD'
19
+ self.money_format = :dollars
20
+ self.homepage_url = 'http://www.quantumgateway.com'
21
+ self.display_name = 'Quantum Gateway'
22
+
23
+ # These are the options that can be used when creating a new Quantum Gateway object.
24
+ #
25
+ # :login => Your Quantum Gateway Gateway ID
26
+ #
27
+ # :password => Your Quantum Gateway Vault Key or Restrict Key
28
+ #
29
+ # NOTE: For testing supply your test GatewayLogin and GatewayKey
30
+ #
31
+ # :email_receipt => true if you want a receipt sent to the customer (false be default)
32
+ #
33
+ # :merchant_receipt => true if you want to override receiving the merchant receipt
34
+ #
35
+ # :ignore_avs => true ignore both AVS and CVV verification
36
+ # :ignore_cvv => true don't want to use CVV so continue processing even if CVV would have failed
37
+ #
38
+ def initialize(options = {})
39
+ requires!(options, :login, :password)
40
+ @options = options
41
+ super
42
+ end
43
+
44
+ # Should run against the test servers or not?
45
+ def test?
46
+ @options[:test] || Base.gateway_mode == :test
47
+ end
48
+
49
+ # Request an authorization for an amount from CyberSource
50
+ #
51
+ def authorize(money, creditcard, options = {})
52
+ setup_address_hash(options)
53
+ commit(build_auth_request(money, creditcard, options), options )
54
+ end
55
+
56
+ # Capture an authorization that has previously been requested
57
+ def capture(money, authorization, options = {})
58
+ setup_address_hash(options)
59
+ commit(build_capture_request(money, authorization, options), options)
60
+ end
61
+
62
+ # Purchase is an auth followed by a capture
63
+ # You must supply an order_id in the options hash
64
+ def purchase(money, creditcard, options = {})
65
+ setup_address_hash(options)
66
+ commit(build_purchase_request(money, creditcard, options), options)
67
+ end
68
+
69
+ def void(identification, options = {})
70
+ commit(build_void_request(identification, options), options)
71
+ end
72
+
73
+ def refund(money, identification, options = {})
74
+ commit(build_credit_request(money, identification, options), options)
75
+ end
76
+
77
+ def credit(money, identification, options = {})
78
+ deprecated CREDIT_DEPRECATION_MESSAGE
79
+ refund(money, identification, options)
80
+ end
81
+
82
+ private
83
+
84
+ def setup_address_hash(options)
85
+ options[:billing_address] = options[:billing_address] || options[:address] || {}
86
+ end
87
+
88
+ def build_auth_request(money, creditcard, options)
89
+ xml = Builder::XmlMarkup.new
90
+ add_common_credit_card_info(xml,'AUTH_ONLY')
91
+ add_purchase_data(xml, money)
92
+ add_creditcard(xml, creditcard)
93
+ add_address(xml, creditcard, options[:billing_address], options)
94
+ add_invoice_details(xml, options)
95
+ add_customer_details(xml, options)
96
+ add_memo(xml, options)
97
+ add_business_rules_data(xml)
98
+ xml.target!
99
+ end
100
+
101
+ def build_capture_request(money, authorization, options)
102
+ xml = Builder::XmlMarkup.new
103
+ add_common_credit_card_info(xml,'PREVIOUS_SALE')
104
+ transaction_id, _ = authorization_parts_from(authorization)
105
+ add_transaction_id(xml, transaction_id)
106
+ xml.target!
107
+ end
108
+
109
+ def build_purchase_request(money, creditcard, options)
110
+ xml = Builder::XmlMarkup.new
111
+ add_common_credit_card_info(xml, @options[:ignore_avs] || @options[:ignore_cvv] ? 'SALES' : 'AUTH_CAPTURE')
112
+ add_address(xml, creditcard, options[:billing_address], options)
113
+ add_purchase_data(xml, money)
114
+ add_creditcard(xml, creditcard)
115
+ add_invoice_details(xml, options)
116
+ add_customer_details(xml, options)
117
+ add_memo(xml, options)
118
+ add_business_rules_data(xml)
119
+ xml.target!
120
+ end
121
+
122
+ def build_void_request(authorization, options)
123
+ xml = Builder::XmlMarkup.new
124
+ add_common_credit_card_info(xml,'VOID')
125
+ transaction_id, _ = authorization_parts_from(authorization)
126
+ add_transaction_id(xml, transaction_id)
127
+ xml.target!
128
+ end
129
+
130
+ def build_credit_request(money, authorization, options)
131
+ xml = Builder::XmlMarkup.new
132
+ add_common_credit_card_info(xml,'RETURN')
133
+ add_purchase_data(xml, money)
134
+ transaction_id, cc = authorization_parts_from(authorization)
135
+ add_transaction_id(xml, transaction_id)
136
+ xml.tag! 'CreditCardNumber', cc
137
+ xml.target!
138
+ end
139
+
140
+ def add_common_credit_card_info(xml, process_type)
141
+ xml.tag! 'RequestType', 'ProcessSingleTransaction'
142
+ xml.tag! 'TransactionType', 'CREDIT'
143
+ xml.tag! 'PaymentType', 'CC'
144
+ xml.tag! 'ProcessType', process_type
145
+ end
146
+
147
+ def add_business_rules_data(xml)
148
+ xml.tag!('CustomerEmail', @options[:email_receipt] ? 'Y' : 'N')
149
+ xml.tag!('MerchantEmail', @options[:merchant_receipt] ? 'Y' : 'N')
150
+ end
151
+
152
+ def add_invoice_details(xml, options)
153
+ xml.tag! 'InvoiceNumber', options[:invoice]
154
+ xml.tag! 'InvoiceDescription', options[:merchant]
155
+ end
156
+
157
+ def add_customer_details(xml, options)
158
+ xml.tag! 'CustomerID', options[:customer]
159
+ end
160
+
161
+ def add_transaction_id(xml, transaction_id)
162
+ xml.tag! 'TransactionID', transaction_id
163
+ end
164
+
165
+ def add_memo(xml, options)
166
+ xml.tag! 'Memo', options[:description]
167
+ end
168
+
169
+ def add_purchase_data(xml, money = 0)
170
+ xml.tag! 'Amount', amount(money)
171
+ xml.tag! 'TransactionDate', Time.now
172
+ end
173
+
174
+ def add_address(xml, creditcard, address, options, shipTo = false)
175
+ xml.tag! 'FirstName', creditcard.first_name
176
+ xml.tag! 'LastName', creditcard.last_name
177
+ xml.tag! 'Address', address[:address1] # => there is no support for address2 in quantum
178
+ xml.tag! 'City', address[:city]
179
+ xml.tag! 'State', address[:state]
180
+ xml.tag! 'ZipCode', address[:zip]
181
+ xml.tag! 'Country', address[:country]
182
+ xml.tag! 'EmailAddress', options[:email]
183
+ xml.tag! 'IPAddress', options[:ip]
184
+ end
185
+
186
+ def add_creditcard(xml, creditcard)
187
+ xml.tag! 'PaymentType', 'CC'
188
+ xml.tag! 'CreditCardNumber', creditcard.number
189
+ xml.tag! 'ExpireMonth', format(creditcard.month, :two_digits)
190
+ xml.tag! 'ExpireYear', format(creditcard.year, :four_digits)
191
+ xml.tag!('CVV2', creditcard.verification_value) unless (@options[:ignore_cvv] || creditcard.verification_value.blank? )
192
+ end
193
+
194
+ # Where we actually build the full SOAP request using builder
195
+ def build_request(body, options)
196
+ xml = Builder::XmlMarkup.new
197
+ xml.instruct!
198
+ xml.tag! 'QGWRequest' do
199
+ xml.tag! 'Authentication' do
200
+ xml.tag! 'GatewayLogin', @options[:login]
201
+ xml.tag! 'GatewayKey', @options[:password]
202
+ end
203
+ xml.tag! 'Request' do
204
+ xml << body
205
+ end
206
+ end
207
+ xml.target!
208
+ end
209
+
210
+ # Contact CyberSource, make the SOAP request, and parse the reply into a Response object
211
+ def commit(request, options)
212
+ headers = { 'Content-Type' => 'text/xml' }
213
+ response = parse(ssl_post(LIVE_URL, build_request(request, options), headers))
214
+
215
+ success = response[:request_status] == "Success"
216
+ message = response[:request_message]
217
+
218
+ if success # => checking for connectivity success first
219
+ success = %w(APPROVED FORCED VOIDED).include?(response[:Status])
220
+ message = response[:StatusDescription]
221
+ authorization = success ? authorization_for(response) : nil
222
+ end
223
+
224
+ Response.new(success, message, response,
225
+ :test => test?,
226
+ :authorization => authorization,
227
+ :avs_result => { :code => response[:AVSResponseCode] },
228
+ :cvv_result => response[:CVV2ResponseCode]
229
+ )
230
+ end
231
+
232
+ # Parse the SOAP response
233
+ # Technique inspired by the Paypal Gateway
234
+ def parse(xml)
235
+ reply = {}
236
+
237
+ begin
238
+ xml = REXML::Document.new(xml)
239
+
240
+ root = REXML::XPath.first(xml, "//QGWRequest/ResponseSummary")
241
+ parse_element(reply, root)
242
+ reply[:request_status] = reply[:Status]
243
+ reply[:request_message] = "#{reply[:Status]}: #{reply[:StatusDescription]}"
244
+
245
+ if root = REXML::XPath.first(xml, "//QGWRequest/Result")
246
+ root.elements.to_a.each do |node|
247
+ parse_element(reply, node)
248
+ end
249
+ end
250
+ rescue Exception => e
251
+ reply[:request_status] = 'Failure'
252
+ reply[:request_message] = "Failure: There was a problem parsing the response XML"
253
+ end
254
+
255
+ return reply
256
+ end
257
+
258
+ def parse_element(reply, node)
259
+ if node.has_elements?
260
+ node.elements.each{|e| parse_element(reply, e) }
261
+ else
262
+ if node.parent.name =~ /item/
263
+ parent = node.parent.name + (node.parent.attributes["id"] ? "_" + node.parent.attributes["id"] : '')
264
+ reply[(parent + '_' + node.name).to_sym] = node.text
265
+ else
266
+ reply[node.name.to_sym] = node.text
267
+ end
268
+ end
269
+ return reply
270
+ end
271
+
272
+ def authorization_for(reply)
273
+ "#{reply[:TransactionID]};#{reply[:CreditCardNumber]}"
274
+ end
275
+
276
+ def authorization_parts_from(authorization)
277
+ authorization.split(/;/)
278
+ end
279
+
280
+ end
281
+ end
282
+ end