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.
- checksums.yaml +7 -0
- data/CHANGELOG +1596 -0
- data/CONTRIBUTORS +511 -0
- data/MIT-LICENSE +20 -0
- data/README.md +18 -0
- data/lib/active_merchant.rb +108 -0
- data/lib/active_merchant/billing.rb +13 -0
- data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
- data/lib/active_merchant/billing/avs_result.rb +98 -0
- data/lib/active_merchant/billing/base.rb +72 -0
- data/lib/active_merchant/billing/check.rb +76 -0
- data/lib/active_merchant/billing/compatibility.rb +120 -0
- data/lib/active_merchant/billing/credit_card.rb +352 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +160 -0
- data/lib/active_merchant/billing/cvv_result.rb +38 -0
- data/lib/active_merchant/billing/gateway.rb +268 -0
- data/lib/active_merchant/billing/gateways.rb +17 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +209 -0
- data/lib/active_merchant/billing/gateways/alfabank.rb +117 -0
- data/lib/active_merchant/billing/gateways/app55.rb +176 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +419 -0
- data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
- data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
- data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
- data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
- data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +188 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +393 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
- data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
- data/lib/active_merchant/billing/gateways/borgun.rb +210 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +515 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
- data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
- data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +220 -0
- data/lib/active_merchant/billing/gateways/cashnet.rb +191 -0
- data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
- data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
- data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
- data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
- data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
- data/lib/active_merchant/billing/gateways/conekta.rb +209 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +709 -0
- data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
- data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
- data/lib/active_merchant/billing/gateways/epay.rb +275 -0
- data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
- data/lib/active_merchant/billing/gateways/eway.rb +214 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +524 -0
- data/lib/active_merchant/billing/gateways/exact.rb +218 -0
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +173 -0
- data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
- data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
- data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
- data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +355 -0
- data/lib/active_merchant/billing/gateways/garanti.rb +257 -0
- data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
- data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
- data/lib/active_merchant/billing/gateways/hps.rb +288 -0
- data/lib/active_merchant/billing/gateways/iats_payments.rb +251 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
- data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
- data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
- data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
- data/lib/active_merchant/billing/gateways/litle.rb +346 -0
- data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
- data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
- data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
- data/lib/active_merchant/billing/gateways/mercury.rb +333 -0
- data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
- data/lib/active_merchant/billing/gateways/migs.rb +265 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
- data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
- data/lib/active_merchant/billing/gateways/moneris_us.rb +291 -0
- data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +280 -0
- data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
- data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
- data/lib/active_merchant/billing/gateways/netbilling.rb +190 -0
- data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
- data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
- data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +313 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +803 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
- data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
- data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +261 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
- data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
- data/lib/active_merchant/billing/gateways/pay_u_latam.rb +462 -0
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
- data/lib/active_merchant/billing/gateways/payex.rb +412 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +304 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +209 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
- data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
- data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
- data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
- data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
- data/lib/active_merchant/billing/gateways/paymill.rb +281 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +117 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +670 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
- data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
- data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
- data/lib/active_merchant/billing/gateways/payway.rb +207 -0
- data/lib/active_merchant/billing/gateways/pin.rb +197 -0
- data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
- data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
- data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
- data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +367 -0
- data/lib/active_merchant/billing/gateways/realex.rb +298 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +391 -0
- data/lib/active_merchant/billing/gateways/sage.rb +175 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +87 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +114 -0
- data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +102 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +398 -0
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
- data/lib/active_merchant/billing/gateways/secure_net.rb +252 -0
- data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +452 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
- data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +411 -0
- data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
- data/lib/active_merchant/billing/gateways/tns.rb +227 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
- data/lib/active_merchant/billing/gateways/transax.rb +23 -0
- data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +254 -0
- data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
- data/lib/active_merchant/billing/gateways/vindicia.rb +385 -0
- data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
- data/lib/active_merchant/billing/gateways/wepay.rb +189 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +421 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
- data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
- data/lib/active_merchant/billing/model.rb +30 -0
- data/lib/active_merchant/billing/payment_token.rb +21 -0
- data/lib/active_merchant/billing/rails.rb +3 -0
- data/lib/active_merchant/billing/response.rb +91 -0
- data/lib/active_merchant/country.rb +332 -0
- data/lib/active_merchant/empty.rb +20 -0
- data/lib/active_merchant/errors.rb +29 -0
- data/lib/active_merchant/offsite_payments_shim.rb +19 -0
- data/lib/active_merchant/version.rb +3 -0
- data/lib/activemerchant.rb +1 -0
- data/lib/support/gateway_support.rb +71 -0
- data/lib/support/outbound_hosts.rb +25 -0
- data/lib/support/ssl_verify.rb +93 -0
- 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
|