yetanothernguyen-activemerchant 1.16.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 (192) hide show
  1. data/CHANGELOG +711 -0
  2. data/CONTRIBUTORS +245 -0
  3. data/MIT-LICENSE +20 -0
  4. data/gem-public_cert.pem +20 -0
  5. data/lib/active_merchant.rb +52 -0
  6. data/lib/active_merchant/billing.rb +9 -0
  7. data/lib/active_merchant/billing/avs_result.rb +98 -0
  8. data/lib/active_merchant/billing/base.rb +57 -0
  9. data/lib/active_merchant/billing/check.rb +68 -0
  10. data/lib/active_merchant/billing/credit_card.rb +178 -0
  11. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  12. data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
  13. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  14. data/lib/active_merchant/billing/expiry_date.rb +34 -0
  15. data/lib/active_merchant/billing/gateway.rb +170 -0
  16. data/lib/active_merchant/billing/gateways.rb +18 -0
  17. data/lib/active_merchant/billing/gateways/authorize_net.rb +672 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
  19. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  20. data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
  21. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -0
  22. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  23. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  24. data/lib/active_merchant/billing/gateways/bogus.rb +142 -0
  25. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  26. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  27. data/lib/active_merchant/billing/gateways/braintree_blue.rb +303 -0
  28. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
  29. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
  30. data/lib/active_merchant/billing/gateways/cyber_source.rb +430 -0
  31. data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
  32. data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
  33. data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
  34. data/lib/active_merchant/billing/gateways/epay.rb +268 -0
  35. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  36. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  37. data/lib/active_merchant/billing/gateways/exact.rb +222 -0
  38. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  39. data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
  40. data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
  41. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  42. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  43. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  44. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  45. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  46. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  47. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  48. data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
  49. data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
  50. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +156 -0
  51. data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
  52. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  53. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
  54. data/lib/active_merchant/billing/gateways/moneris.rb +209 -0
  55. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  56. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  57. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  58. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  59. data/lib/active_merchant/billing/gateways/ogone.rb +292 -0
  60. data/lib/active_merchant/billing/gateways/orbital.rb +321 -0
  61. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  62. data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
  63. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  64. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  65. data/lib/active_merchant/billing/gateways/payflow.rb +253 -0
  66. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
  67. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  68. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  69. data/lib/active_merchant/billing/gateways/payflow_express.rb +222 -0
  70. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  71. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  72. data/lib/active_merchant/billing/gateways/payment_express.rb +235 -0
  73. data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
  74. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +351 -0
  75. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
  76. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  77. data/lib/active_merchant/billing/gateways/paypal_express.rb +177 -0
  78. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  79. data/lib/active_merchant/billing/gateways/paystation.rb +201 -0
  80. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  81. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  82. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  83. data/lib/active_merchant/billing/gateways/qbms.rb +293 -0
  84. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  85. data/lib/active_merchant/billing/gateways/quickpay.rb +223 -0
  86. data/lib/active_merchant/billing/gateways/realex.rb +311 -0
  87. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  88. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  89. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  90. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  91. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  92. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  93. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  94. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  95. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
  96. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  97. data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
  98. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  99. data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
  100. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  101. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  102. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  103. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  104. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  105. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  106. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  107. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  108. data/lib/active_merchant/billing/integrations.rb +17 -0
  109. data/lib/active_merchant/billing/integrations/action_view_helper.rb +70 -0
  110. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  111. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  112. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  113. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  114. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  115. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  116. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  117. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  118. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  119. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  120. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  121. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  122. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  123. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  124. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  125. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  126. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  127. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  128. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  129. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  130. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  131. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  132. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  133. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  134. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  135. data/lib/active_merchant/billing/integrations/helper.rb +96 -0
  136. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  137. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  138. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  139. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  140. data/lib/active_merchant/billing/integrations/migs.rb +22 -0
  141. data/lib/active_merchant/billing/integrations/migs/helper.rb +64 -0
  142. data/lib/active_merchant/billing/integrations/migs/return.rb +54 -0
  143. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  144. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  145. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  146. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  147. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  148. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  149. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  150. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  151. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  152. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  153. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  154. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  155. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  156. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  157. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  158. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  159. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  160. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  161. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  162. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  163. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  164. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  165. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  166. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  167. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  168. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  169. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  170. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  171. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  172. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  173. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  174. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  175. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  176. data/lib/active_merchant/billing/response.rb +32 -0
  177. data/lib/active_merchant/common.rb +14 -0
  178. data/lib/active_merchant/common/connection.rb +177 -0
  179. data/lib/active_merchant/common/country.rb +328 -0
  180. data/lib/active_merchant/common/error.rb +26 -0
  181. data/lib/active_merchant/common/post_data.rb +24 -0
  182. data/lib/active_merchant/common/posts_data.rb +63 -0
  183. data/lib/active_merchant/common/requires_parameters.rb +16 -0
  184. data/lib/active_merchant/common/utils.rb +22 -0
  185. data/lib/active_merchant/common/validateable.rb +81 -0
  186. data/lib/active_merchant/railtie.rb +9 -0
  187. data/lib/active_merchant/version.rb +3 -0
  188. data/lib/activemerchant.rb +1 -0
  189. data/lib/certs/cacert.pem +7815 -0
  190. data/lib/support/gateway_support.rb +58 -0
  191. data/lib/support/outbound_hosts.rb +25 -0
  192. metadata +281 -0
@@ -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
@@ -0,0 +1,223 @@
1
+ require 'rexml/document'
2
+ require 'digest/md5'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class QuickpayGateway < Gateway
7
+ URL = 'https://secure.quickpay.dk/api'
8
+
9
+ self.default_currency = 'DKK'
10
+ self.money_format = :cents
11
+ self.supported_cardtypes = [ :dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ]
12
+ self.supported_countries = ['DK', 'SE']
13
+ self.homepage_url = 'http://quickpay.dk/'
14
+ self.display_name = 'Quickpay'
15
+
16
+ PROTOCOL = 3
17
+
18
+ MD5_CHECK_FIELDS = {
19
+ :authorize => [:protocol, :msgtype, :merchant, :ordernumber, :amount, :currency, :autocapture, :cardnumber, :expirationdate, :cvd, :cardtypelock, :testmode],
20
+ :capture => [:protocol, :msgtype, :merchant, :amount, :transaction],
21
+ :cancel => [:protocol, :msgtype, :merchant, :transaction],
22
+ :refund => [:protocol, :msgtype, :merchant, :amount, :transaction],
23
+ :subscribe => [:protocol, :msgtype, :merchant, :ordernumber, :cardnumber, :expirationdate, :cvd, :cardtypelock, :description, :testmode],
24
+ :recurring => [:protocol, :msgtype, :merchant, :ordernumber, :amount, :currency, :autocapture, :transaction],
25
+ :status => [:protocol, :msgtype, :merchant, :transaction],
26
+ :chstatus => [:protocol, :msgtype, :merchant],
27
+ }
28
+
29
+ APPROVED = '000'
30
+
31
+ # The login is the QuickpayId
32
+ # The password is the md5checkword from the Quickpay admin interface
33
+ def initialize(options = {})
34
+ requires!(options, :login, :password)
35
+ @options = options
36
+ super
37
+ end
38
+
39
+ def authorize(money, credit_card_or_reference, options = {})
40
+ post = {}
41
+
42
+ add_amount(post, money, options)
43
+ add_invoice(post, options)
44
+ add_creditcard_or_reference(post, credit_card_or_reference, options)
45
+ add_autocapture(post, false)
46
+ add_testmode(post)
47
+
48
+ commit(recurring_or_authorize(credit_card_or_reference), post)
49
+ end
50
+
51
+ def purchase(money, credit_card_or_reference, options = {})
52
+ post = {}
53
+
54
+ add_amount(post, money, options)
55
+ add_creditcard_or_reference(post, credit_card_or_reference, options)
56
+ add_invoice(post, options)
57
+ add_autocapture(post, true)
58
+
59
+ commit(recurring_or_authorize(credit_card_or_reference), post)
60
+ end
61
+
62
+ def capture(money, authorization, options = {})
63
+ post = {}
64
+
65
+ add_reference(post, authorization)
66
+ add_amount_without_currency(post, money)
67
+
68
+ commit(:capture, post)
69
+ end
70
+
71
+ def void(identification, options = {})
72
+ post = {}
73
+
74
+ add_reference(post, identification)
75
+
76
+ commit(:cancel, post)
77
+ end
78
+
79
+ def refund(money, identification, options = {})
80
+ post = {}
81
+
82
+ add_amount_without_currency(post, money)
83
+ add_reference(post, identification)
84
+
85
+ commit(:refund, post)
86
+ end
87
+
88
+ def credit(money, identification, options = {})
89
+ deprecated CREDIT_DEPRECATION_MESSAGE
90
+ refund(money, identification, options)
91
+ end
92
+
93
+ def store(creditcard, options = {})
94
+ post = {}
95
+
96
+ add_creditcard(post, creditcard, options)
97
+ add_invoice(post, options)
98
+ add_description(post, options)
99
+ add_testmode(post)
100
+
101
+ commit(:subscribe, post)
102
+ end
103
+
104
+ private
105
+
106
+ def add_amount(post, money, options = {})
107
+ post[:amount] = amount(money)
108
+ post[:currency] = options[:currency] || currency(money)
109
+ end
110
+
111
+ def add_amount_without_currency(post, money, options = {})
112
+ post[:amount] = amount(money)
113
+ end
114
+
115
+ def add_invoice(post, options)
116
+ post[:ordernumber] = format_order_number(options[:order_id])
117
+ end
118
+
119
+ def add_creditcard(post, credit_card, options)
120
+ post[:cardnumber] = credit_card.number
121
+ post[:cvd] = credit_card.verification_value
122
+ post[:expirationdate] = expdate(credit_card)
123
+ post[:cardtypelock] = options[:cardtypelock] unless options[:cardtypelock].blank?
124
+ end
125
+
126
+ def add_reference(post, identification)
127
+ post[:transaction] = identification
128
+ end
129
+
130
+ def add_creditcard_or_reference(post, credit_card_or_reference, options)
131
+ if credit_card_or_reference.is_a?(String)
132
+ add_reference(post, credit_card_or_reference)
133
+ else
134
+ add_creditcard(post, credit_card_or_reference, options)
135
+ end
136
+ end
137
+
138
+ def add_autocapture(post, autocapture)
139
+ post[:autocapture] = autocapture ? 1 : 0
140
+ end
141
+
142
+ def recurring_or_authorize(credit_card_or_reference)
143
+ credit_card_or_reference.is_a?(String) ? :recurring : :authorize
144
+ end
145
+
146
+ def add_description(post, options)
147
+ post[:description] = options[:description]
148
+ end
149
+
150
+ def add_testmode(post)
151
+ post[:testmode] = test? ? '1' : '0'
152
+ end
153
+
154
+ def commit(action, params)
155
+ response = parse(ssl_post(URL, post_data(action, params)))
156
+
157
+ Response.new(successful?(response), message_from(response), response,
158
+ :test => test?,
159
+ :authorization => response[:transaction]
160
+ )
161
+ end
162
+
163
+ def successful?(response)
164
+ response[:qpstat] == APPROVED
165
+ end
166
+
167
+ def parse(data)
168
+ response = {}
169
+
170
+ doc = REXML::Document.new(data)
171
+
172
+ doc.root.elements.each do |element|
173
+ response[element.name.to_sym] = element.text
174
+ end
175
+
176
+ response
177
+ end
178
+
179
+ def message_from(response)
180
+ case response[:qpstat]
181
+ when '008' # Error in request data
182
+ response[:qpstatmsg].to_s
183
+ #.scan(/[A-Z][a-z0-9 \/]+/).to_sentence
184
+ else
185
+ response[:qpstatmsg].to_s
186
+ end
187
+ end
188
+
189
+ def post_data(action, params = {})
190
+ params[:protocol] = PROTOCOL
191
+ params[:msgtype] = action.to_s
192
+ params[:merchant] = @options[:login]
193
+ params[:md5check] = generate_check_hash(action, params)
194
+
195
+ params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
196
+ end
197
+
198
+ def generate_check_hash(action, params)
199
+ string = MD5_CHECK_FIELDS[action].collect do |key|
200
+ params[key]
201
+ end.join('')
202
+
203
+ # Add the md5checkword
204
+ string << @options[:password].to_s
205
+
206
+ Digest::MD5.hexdigest(string)
207
+ end
208
+
209
+ def expdate(credit_card)
210
+ year = format(credit_card.year, :two_digits)
211
+ month = format(credit_card.month, :two_digits)
212
+
213
+ "#{year}#{month}"
214
+ end
215
+
216
+ # Limited to 20 digits max
217
+ def format_order_number(number)
218
+ number.to_s.gsub(/[^\w_]/, '').rjust(4, "0")[0...20]
219
+ end
220
+ end
221
+ end
222
+ end
223
+