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,303 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # For more information on the Metrics Global Payment Gateway, visit the {Metrics Global website}[www.metricsglobal.com].
4
+ # Further documentation on AVS and CVV response codes are available under the support section of the Metrics Global
5
+ # control panel.
6
+ #
7
+ # === Metrics Global Payment Gateway Authentication
8
+ #
9
+ # The login and password for the gateway are the same as the username and password used to log in to the Metrics Global
10
+ # control panel. Contact Metrics Global support to receive credentials for the control panel.
11
+ #
12
+ # === Demo Account
13
+ #
14
+ # There is a public demo account available with the following credentials:
15
+ #
16
+ # Login: demo
17
+ # Password: password
18
+ class MetricsGlobalGateway < Gateway
19
+ API_VERSION = '3.1'
20
+
21
+ class_attribute :test_url, :live_url
22
+
23
+ self.test_url = "https://secure.metricsglobalgateway.com/gateway/transact.dll?testing=true"
24
+ self.live_url = "https://secure.metricsglobalgateway.com/gateway/transact.dll"
25
+
26
+ class_attribute :duplicate_window
27
+
28
+ APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
29
+
30
+ RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT = 0, 2, 3
31
+ AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE = 5, 6, 38
32
+
33
+ self.supported_countries = ['US']
34
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
35
+ self.homepage_url = 'http://www.metricsglobal.com'
36
+ self.display_name = 'Metrics Global'
37
+
38
+ CARD_CODE_ERRORS = %w( N S )
39
+ AVS_ERRORS = %w( A E N R W Z )
40
+ AVS_REASON_CODES = %w(27 45)
41
+
42
+ # Creates a new MetricsGlobalGateway
43
+ #
44
+ # The gateway requires that a valid login and password be passed
45
+ # in the +options+ hash.
46
+ #
47
+ # ==== Options
48
+ #
49
+ # * <tt>:login</tt> -- The username required to access the Metrics Global control panel. (REQUIRED)
50
+ # * <tt>:password</tt> -- The password required to access the Metrics Global control panel. (REQUIRED)
51
+ # * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
52
+ # Otherwise, perform transactions against the production server.
53
+ def initialize(options = {})
54
+ requires!(options, :login, :password)
55
+ super
56
+ end
57
+
58
+ # Performs an authorization, which reserves the funds on the customer's credit card, but does not
59
+ # charge the card.
60
+ #
61
+ # ==== Parameters
62
+ #
63
+ # * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
64
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
65
+ # * <tt>options</tt> -- A hash of optional parameters.
66
+ def authorize(money, creditcard, options = {})
67
+ post = {}
68
+ add_invoice(post, options)
69
+ add_creditcard(post, creditcard)
70
+ add_address(post, options)
71
+ add_customer_data(post, options)
72
+ add_duplicate_window(post)
73
+
74
+ commit('AUTH_ONLY', money, post)
75
+ end
76
+
77
+ # Perform a purchase, which is essentially an authorization and capture in a single operation.
78
+ #
79
+ # ==== Parameters
80
+ #
81
+ # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
82
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
83
+ # * <tt>options</tt> -- A hash of optional parameters.
84
+ def purchase(money, creditcard, options = {})
85
+ post = {}
86
+ add_invoice(post, options)
87
+ add_creditcard(post, creditcard)
88
+ add_address(post, options)
89
+ add_customer_data(post, options)
90
+ add_duplicate_window(post)
91
+
92
+ commit('AUTH_CAPTURE', money, post)
93
+ end
94
+
95
+ # Captures the funds from an authorized transaction.
96
+ #
97
+ # ==== Parameters
98
+ #
99
+ # * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
100
+ # * <tt>authorization</tt> -- The authorization returned from the previous authorize request.
101
+ def capture(money, authorization, options = {})
102
+ post = {:trans_id => authorization}
103
+ add_customer_data(post, options)
104
+ commit('PRIOR_AUTH_CAPTURE', money, post)
105
+ end
106
+
107
+ # Void a previous transaction
108
+ #
109
+ # ==== Parameters
110
+ #
111
+ # * <tt>authorization</tt> - The authorization returned from the previous authorize request.
112
+ def void(authorization, options = {})
113
+ post = {:trans_id => authorization}
114
+ add_duplicate_window(post)
115
+ commit('VOID', nil, post)
116
+ end
117
+
118
+ # Refund a transaction.
119
+ #
120
+ # This transaction indicates to the gateway that
121
+ # money should flow from the merchant to the customer.
122
+ #
123
+ # ==== Parameters
124
+ #
125
+ # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
126
+ # * <tt>identification</tt> -- The ID of the original transaction against which the refund is being issued.
127
+ # * <tt>options</tt> -- A hash of parameters.
128
+ #
129
+ # ==== Options
130
+ #
131
+ # * <tt>:card_number</tt> -- The credit card number the refund is being issued to. (REQUIRED)
132
+ # * <tt>:first_name</tt> -- The first name of the account being refunded.
133
+ # * <tt>:last_name</tt> -- The last name of the account being refunded.
134
+ # * <tt>:zip</tt> -- The postal code of the account being refunded.
135
+ def refund(money, identification, options = {})
136
+ requires!(options, :card_number)
137
+
138
+ post = { :trans_id => identification,
139
+ :card_num => options[:card_number]
140
+ }
141
+
142
+ post[:first_name] = options[:first_name] if options[:first_name]
143
+ post[:last_name] = options[:last_name] if options[:last_name]
144
+ post[:zip] = options[:zip] if options[:zip]
145
+
146
+ add_invoice(post, options)
147
+ add_duplicate_window(post)
148
+
149
+ commit('CREDIT', money, post)
150
+ end
151
+
152
+ def credit(money, identification, options = {})
153
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
154
+ refund(money, identification, options)
155
+ end
156
+
157
+ private
158
+
159
+ def commit(action, money, parameters)
160
+ parameters[:amount] = amount(money) unless action == 'VOID'
161
+
162
+ # Only activate the test_request when the :test option is passed in
163
+ parameters[:test_request] = @options[:test] ? 'TRUE' : 'FALSE'
164
+
165
+ url = test? ? self.test_url : self.live_url
166
+ data = ssl_post url, post_data(action, parameters)
167
+
168
+ response = parse(data)
169
+
170
+ message = message_from(response)
171
+
172
+ # Return the response. The authorization can be taken out of the transaction_id
173
+ # Test Mode on/off is something we have to parse from the response text.
174
+ # It usually looks something like this
175
+ #
176
+ # (TESTMODE) Successful Sale
177
+ test_mode = test? || message =~ /TESTMODE/
178
+
179
+ Response.new(success?(response), message, response,
180
+ :test => test_mode,
181
+ :authorization => response[:transaction_id],
182
+ :fraud_review => fraud_review?(response),
183
+ :avs_result => { :code => response[:avs_result_code] },
184
+ :cvv_result => response[:card_code]
185
+ )
186
+ end
187
+
188
+ def success?(response)
189
+ response[:response_code] == APPROVED
190
+ end
191
+
192
+ def fraud_review?(response)
193
+ response[:response_code] == FRAUD_REVIEW
194
+ end
195
+
196
+ def parse(body)
197
+ fields = split(body)
198
+
199
+ results = {
200
+ :response_code => fields[RESPONSE_CODE].to_i,
201
+ :response_reason_code => fields[RESPONSE_REASON_CODE],
202
+ :response_reason_text => fields[RESPONSE_REASON_TEXT],
203
+ :avs_result_code => fields[AVS_RESULT_CODE],
204
+ :transaction_id => fields[TRANSACTION_ID],
205
+ :card_code => fields[CARD_CODE_RESPONSE_CODE]
206
+ }
207
+ results
208
+ end
209
+
210
+ def post_data(action, parameters = {})
211
+ post = {}
212
+
213
+ post[:version] = API_VERSION
214
+ post[:login] = @options[:login]
215
+ post[:tran_key] = @options[:password]
216
+ post[:relay_response] = "FALSE"
217
+ post[:type] = action
218
+ post[:delim_data] = "TRUE"
219
+ post[:delim_char] = ","
220
+ post[:encap_char] = "$"
221
+ post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
222
+
223
+ request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
224
+ request
225
+ end
226
+
227
+ def add_invoice(post, options)
228
+ post[:invoice_num] = options[:order_id]
229
+ post[:description] = options[:description]
230
+ end
231
+
232
+ def add_creditcard(post, creditcard)
233
+ post[:card_num] = creditcard.number
234
+ post[:card_code] = creditcard.verification_value if creditcard.verification_value?
235
+ post[:exp_date] = expdate(creditcard)
236
+ post[:first_name] = creditcard.first_name
237
+ post[:last_name] = creditcard.last_name
238
+ end
239
+
240
+ def add_customer_data(post, options)
241
+ if options.has_key? :email
242
+ post[:email] = options[:email]
243
+ post[:email_customer] = false
244
+ end
245
+
246
+ if options.has_key? :customer
247
+ post[:cust_id] = options[:customer]
248
+ end
249
+
250
+ if options.has_key? :ip
251
+ post[:customer_ip] = options[:ip]
252
+ end
253
+ end
254
+
255
+ # x_duplicate_window won't be sent by default, because sending it changes the response.
256
+ # "If this field is present in the request with or without a value, an enhanced duplicate transaction response will be sent."
257
+ def add_duplicate_window(post)
258
+ unless duplicate_window.nil?
259
+ post[:duplicate_window] = duplicate_window
260
+ end
261
+ end
262
+
263
+ def add_address(post, options)
264
+ if address = options[:billing_address] || options[:address]
265
+ post[:address] = address[:address1].to_s
266
+ post[:company] = address[:company].to_s
267
+ post[:phone] = address[:phone].to_s
268
+ post[:zip] = address[:zip].to_s
269
+ post[:city] = address[:city].to_s
270
+ post[:country] = address[:country].to_s
271
+ post[:state] = address[:state].blank? ? 'n/a' : address[:state]
272
+ end
273
+
274
+ if address = options[:shipping_address]
275
+ post[:ship_to_first_name] = address[:first_name].to_s
276
+ post[:ship_to_last_name] = address[:last_name].to_s
277
+ post[:ship_to_address] = address[:address1].to_s
278
+ post[:ship_to_company] = address[:company].to_s
279
+ post[:ship_to_phone] = address[:phone].to_s
280
+ post[:ship_to_zip] = address[:zip].to_s
281
+ post[:ship_to_city] = address[:city].to_s
282
+ post[:ship_to_country] = address[:country].to_s
283
+ post[:ship_to_state] = address[:state].blank? ? 'n/a' : address[:state]
284
+ end
285
+ end
286
+
287
+ def message_from(results)
288
+ if results[:response_code] == DECLINED
289
+ return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
290
+ if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
291
+ return AVSResult.messages[ results[:avs_result_code] ]
292
+ end
293
+ end
294
+
295
+ (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
296
+ end
297
+
298
+ def split(response)
299
+ response[1..-2].split(/\$,\$/)
300
+ end
301
+ end
302
+ end
303
+ end
@@ -0,0 +1,265 @@
1
+ require File.dirname(__FILE__) + '/migs/migs_codes'
2
+
3
+ require 'digest/md5' # Used in add_secure_hash
4
+
5
+ module ActiveMerchant #:nodoc:
6
+ module Billing #:nodoc:
7
+ class MigsGateway < Gateway
8
+ include MigsCodes
9
+
10
+ API_VERSION = 1
11
+
12
+ class_attribute :server_hosted_url, :merchant_hosted_url
13
+
14
+ self.server_hosted_url = 'https://migs.mastercard.com.au/vpcpay'
15
+ self.merchant_hosted_url = 'https://migs.mastercard.com.au/vpcdps'
16
+
17
+ self.live_url = self.server_hosted_url
18
+
19
+ # MiGS is supported throughout Asia Pacific, Middle East and Africa
20
+ # MiGS is used in Australia (AU) by ANZ (eGate), CBA (CommWeb) and more
21
+ # Source of Country List: http://www.scribd.com/doc/17811923
22
+ self.supported_countries = %w(AU AE BD BN EG HK ID IN JO KW LB LK MU MV MY NZ OM PH QA SA SG TT VN)
23
+
24
+ # The card types supported by the payment gateway
25
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
26
+
27
+ self.money_format = :cents
28
+
29
+ # The homepage URL of the gateway
30
+ self.homepage_url = 'http://mastercard.com/mastercardsps'
31
+
32
+ # The name of the gateway
33
+ self.display_name = 'MasterCard Internet Gateway Service (MiGS)'
34
+
35
+ # Creates a new MigsGateway
36
+ # The advanced_login/advanced_password fields are needed for
37
+ # advanced methods such as the capture, refund and status methods
38
+ #
39
+ # ==== Options
40
+ #
41
+ # * <tt>:login</tt> -- The MiGS Merchant ID (REQUIRED)
42
+ # * <tt>:password</tt> -- The MiGS Access Code (REQUIRED)
43
+ # * <tt>:secure_hash</tt> -- The MiGS Secure Hash
44
+ # (Required for Server Hosted payments)
45
+ # * <tt>:advanced_login</tt> -- The MiGS AMA User
46
+ # * <tt>:advanced_password</tt> -- The MiGS AMA User's password
47
+ def initialize(options = {})
48
+ requires!(options, :login, :password)
49
+ super
50
+ end
51
+
52
+ # ==== Options
53
+ #
54
+ # * <tt>:order_id</tt> -- A reference for tracking the order (REQUIRED)
55
+ # * <tt>:unique_id</tt> -- A unique id for this request (Max 40 chars).
56
+ # If not supplied one will be generated.
57
+ def purchase(money, creditcard, options = {})
58
+ requires!(options, :order_id)
59
+
60
+ post = {}
61
+ post[:Amount] = amount(money)
62
+ add_invoice(post, options)
63
+ add_creditcard(post, creditcard)
64
+ add_standard_parameters('pay', post, options[:unique_id])
65
+
66
+ commit(post)
67
+ end
68
+
69
+ # MiGS works by merchants being either purchase only or authorize/capture
70
+ # So authorize is the same as purchase when in authorize mode
71
+ alias_method :authorize, :purchase
72
+
73
+ # ==== Options
74
+ #
75
+ # * <tt>:unique_id</tt> -- A unique id for this request (Max 40 chars).
76
+ # If not supplied one will be generated.
77
+ def capture(money, authorization, options = {})
78
+ requires!(@options, :advanced_login, :advanced_password)
79
+
80
+ post = options.merge(:TransNo => authorization)
81
+ post[:Amount] = amount(money)
82
+ add_advanced_user(post)
83
+ add_standard_parameters('capture', post, options[:unique_id])
84
+
85
+ commit(post)
86
+ end
87
+
88
+ # ==== Options
89
+ #
90
+ # * <tt>:unique_id</tt> -- A unique id for this request (Max 40 chars).
91
+ # If not supplied one will be generated.
92
+ def refund(money, authorization, options = {})
93
+ requires!(@options, :advanced_login, :advanced_password)
94
+
95
+ post = options.merge(:TransNo => authorization)
96
+ post[:Amount] = amount(money)
97
+ add_advanced_user(post)
98
+ add_standard_parameters('refund', post, options[:unique_id])
99
+
100
+ commit(post)
101
+ end
102
+
103
+ def credit(money, authorization, options = {})
104
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
105
+ refund(money, authorization, options)
106
+ end
107
+
108
+ # Checks the status of a previous transaction
109
+ # This can be useful when a response is not received due to network issues
110
+ #
111
+ # ==== Parameters
112
+ #
113
+ # * <tt>unique_id</tt> -- Unique id of transaction to find.
114
+ # This is the value of the option supplied in other methods or
115
+ # if not supplied is returned with key :MerchTxnRef
116
+ def status(unique_id)
117
+ requires!(@options, :advanced_login, :advanced_password)
118
+
119
+ post = {}
120
+ add_advanced_user(post)
121
+ add_standard_parameters('queryDR', post, unique_id)
122
+
123
+ commit(post)
124
+ end
125
+
126
+ # Generates a URL to redirect user to MiGS to process payment
127
+ # Once user is finished MiGS will redirect back to specified URL
128
+ # With a response hash which can be turned into a Response object
129
+ # with purchase_offsite_response
130
+ #
131
+ # ==== Options
132
+ #
133
+ # * <tt>:order_id</tt> -- A reference for tracking the order (REQUIRED)
134
+ # * <tt>:locale</tt> -- Change the language of the redirected page
135
+ # Values are 2 digit locale, e.g. en, es
136
+ # * <tt>:return_url</tt> -- the URL to return to once the payment is complete
137
+ # * <tt>:card_type</tt> -- Providing this skips the card type step.
138
+ # Values are ActiveMerchant formats: e.g. master, visa, american_express, diners_club
139
+ # * <tt>:unique_id</tt> -- Unique id of transaction to find.
140
+ # If not supplied one will be generated.
141
+ def purchase_offsite_url(money, options = {})
142
+ requires!(options, :order_id, :return_url)
143
+ requires!(@options, :secure_hash)
144
+
145
+ post = {}
146
+ post[:Amount] = amount(money)
147
+ add_invoice(post, options)
148
+ add_creditcard_type(post, options[:card_type]) if options[:card_type]
149
+
150
+ post.merge!(
151
+ :Locale => options[:locale] || 'en',
152
+ :ReturnURL => options[:return_url]
153
+ )
154
+
155
+ add_standard_parameters('pay', post, options[:unique_id])
156
+
157
+ add_secure_hash(post)
158
+
159
+ self.server_hosted_url + '?' + post_data(post)
160
+ end
161
+
162
+ # Parses a response from purchase_offsite_url once user is redirected back
163
+ #
164
+ # ==== Parameters
165
+ #
166
+ # * <tt>data</tt> -- All params when offsite payment returns
167
+ # e.g. returns to http://company.com/return?a=1&b=2, then input "a=1&b=2"
168
+ def purchase_offsite_response(data)
169
+ requires!(@options, :secure_hash)
170
+
171
+ response_hash = parse(data)
172
+
173
+ expected_secure_hash = calculate_secure_hash(response_hash.reject{|k, v| k == :SecureHash}, @options[:secure_hash])
174
+ unless response_hash[:SecureHash] == expected_secure_hash
175
+ raise SecurityError, "Secure Hash mismatch, response may be tampered with"
176
+ end
177
+
178
+ response_object(response_hash)
179
+ end
180
+
181
+ def test?
182
+ @options[:login].start_with?('TEST')
183
+ end
184
+
185
+ private
186
+
187
+ def add_advanced_user(post)
188
+ post[:User] = @options[:advanced_login]
189
+ post[:Password] = @options[:advanced_password]
190
+ end
191
+
192
+ def add_invoice(post, options)
193
+ post[:OrderInfo] = options[:order_id]
194
+ end
195
+
196
+ def add_creditcard(post, creditcard)
197
+ post[:CardNum] = creditcard.number
198
+ post[:CardSecurityCode] = creditcard.verification_value if creditcard.verification_value?
199
+ post[:CardExp] = format(creditcard.year, :two_digits) + format(creditcard.month, :two_digits)
200
+ end
201
+
202
+ def add_creditcard_type(post, card_type)
203
+ post[:Gateway] = 'ssl'
204
+ post[:card] = CARD_TYPES.detect{|ct| ct.am_code == card_type}.migs_long_code
205
+ end
206
+
207
+ def parse(body)
208
+ params = CGI::parse(body)
209
+ hash = {}
210
+ params.each do |key, value|
211
+ hash[key.gsub('vpc_', '').to_sym] = value[0]
212
+ end
213
+ hash
214
+ end
215
+
216
+ def commit(post)
217
+ data = ssl_post self.merchant_hosted_url, post_data(post)
218
+ response_hash = parse(data)
219
+ response_object(response_hash)
220
+ end
221
+
222
+ def response_object(response)
223
+ Response.new(success?(response), response[:Message], response,
224
+ :test => test?,
225
+ :authorization => response[:TransactionNo],
226
+ :fraud_review => fraud_review?(response),
227
+ :avs_result => { :code => response[:AVSResultCode] },
228
+ :cvv_result => response[:CSCResultCode]
229
+ )
230
+ end
231
+
232
+ def success?(response)
233
+ response[:TxnResponseCode] == '0'
234
+ end
235
+
236
+ def fraud_review?(response)
237
+ ISSUER_RESPONSE_CODES[response[:AcqResponseCode]] == 'Suspected Fraud'
238
+ end
239
+
240
+ def add_standard_parameters(action, post, unique_id = nil)
241
+ post.merge!(
242
+ :Version => API_VERSION,
243
+ :Merchant => @options[:login],
244
+ :AccessCode => @options[:password],
245
+ :Command => action,
246
+ :MerchTxnRef => unique_id || generate_unique_id.slice(0, 40)
247
+ )
248
+ end
249
+
250
+ def post_data(post)
251
+ post.collect { |key, value| "vpc_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
252
+ end
253
+
254
+ def add_secure_hash(post)
255
+ post[:SecureHash] = calculate_secure_hash(post, @options[:secure_hash])
256
+ end
257
+
258
+ def calculate_secure_hash(post, secure_hash)
259
+ sorted_values = post.sort_by(&:to_s).map(&:last)
260
+ input = secure_hash + sorted_values.join
261
+ Digest::MD5.hexdigest(input).upcase
262
+ end
263
+ end
264
+ end
265
+ end