start_activemerchant 1.50.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 (218) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1769 -0
  3. data/CONTRIBUTORS +540 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +226 -0
  6. data/lib/active_merchant.rb +67 -0
  7. data/lib/active_merchant/billing.rb +15 -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 +404 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +195 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +291 -0
  18. data/lib/active_merchant/billing/gateways.rb +14 -0
  19. data/lib/active_merchant/billing/gateways/allied_wallet.rb +203 -0
  20. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  21. data/lib/active_merchant/billing/gateways/authorize_net.rb +510 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  24. data/lib/active_merchant/billing/gateways/axcessms.rb +181 -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 +192 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +389 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +58 -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 +211 -0
  37. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  39. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  40. data/lib/active_merchant/billing/gateways/braintree_blue.rb +574 -0
  41. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  42. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  43. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  44. data/lib/active_merchant/billing/gateways/card_stream.rb +238 -0
  45. data/lib/active_merchant/billing/gateways/cashnet.rb +202 -0
  46. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  47. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  48. data/lib/active_merchant/billing/gateways/cenpos.rb +262 -0
  49. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  50. data/lib/active_merchant/billing/gateways/checkout.rb +216 -0
  51. data/lib/active_merchant/billing/gateways/checkout_v2.rb +200 -0
  52. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  53. data/lib/active_merchant/billing/gateways/conekta.rb +210 -0
  54. data/lib/active_merchant/billing/gateways/cyber_source.rb +720 -0
  55. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  56. data/lib/active_merchant/billing/gateways/dibs.rb +206 -0
  57. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  58. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  59. data/lib/active_merchant/billing/gateways/epay.rb +274 -0
  60. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  61. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  62. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  63. data/lib/active_merchant/billing/gateways/eway_rapid.rb +522 -0
  64. data/lib/active_merchant/billing/gateways/exact.rb +227 -0
  65. data/lib/active_merchant/billing/gateways/ezic.rb +206 -0
  66. data/lib/active_merchant/billing/gateways/fat_zebra.rb +213 -0
  67. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  68. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  69. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  70. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  71. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +413 -0
  72. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  73. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  74. data/lib/active_merchant/billing/gateways/garanti.rb +261 -0
  75. data/lib/active_merchant/billing/gateways/global_transport.rb +179 -0
  76. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  77. data/lib/active_merchant/billing/gateways/hps.rb +287 -0
  78. data/lib/active_merchant/billing/gateways/iats_payments.rb +277 -0
  79. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  80. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  81. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  82. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  83. data/lib/active_merchant/billing/gateways/inspire.rb +219 -0
  84. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  85. data/lib/active_merchant/billing/gateways/ipp.rb +175 -0
  86. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  87. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  88. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  89. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  90. data/lib/active_merchant/billing/gateways/litle.rb +345 -0
  91. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  92. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  93. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  94. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  95. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  96. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  97. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  98. data/lib/active_merchant/billing/gateways/mercury.rb +326 -0
  99. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  100. data/lib/active_merchant/billing/gateways/migs.rb +280 -0
  101. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  102. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  103. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  104. data/lib/active_merchant/billing/gateways/monei.rb +307 -0
  105. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  106. data/lib/active_merchant/billing/gateways/moneris_us.rb +298 -0
  107. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  108. data/lib/active_merchant/billing/gateways/nab_transact.rb +290 -0
  109. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  110. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  111. data/lib/active_merchant/billing/gateways/netbilling.rb +224 -0
  112. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  113. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  114. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  115. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  116. data/lib/active_merchant/billing/gateways/omise.rb +319 -0
  117. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  118. data/lib/active_merchant/billing/gateways/optimal_payment.rb +314 -0
  119. data/lib/active_merchant/billing/gateways/orbital.rb +834 -0
  120. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  121. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  122. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  123. data/lib/active_merchant/billing/gateways/pay_conex.rb +246 -0
  124. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +277 -0
  125. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  126. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  127. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  128. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  129. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  130. data/lib/active_merchant/billing/gateways/payflow.rb +308 -0
  131. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +220 -0
  132. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  133. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  134. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  135. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  136. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  137. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  138. data/lib/active_merchant/billing/gateways/paymill.rb +282 -0
  139. data/lib/active_merchant/billing/gateways/paypal.rb +129 -0
  140. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +679 -0
  141. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  142. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  143. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  144. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  145. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  146. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  147. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  148. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  149. data/lib/active_merchant/billing/gateways/payu_in.rb +247 -0
  150. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  151. data/lib/active_merchant/billing/gateways/pin.rb +207 -0
  152. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  153. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  154. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  155. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  156. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  157. data/lib/active_merchant/billing/gateways/quickbooks.rb +280 -0
  158. data/lib/active_merchant/billing/gateways/quickpay.rb +26 -0
  159. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +188 -0
  160. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +240 -0
  161. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +227 -0
  162. data/lib/active_merchant/billing/gateways/qvalent.rb +179 -0
  163. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  164. data/lib/active_merchant/billing/gateways/redsys.rb +406 -0
  165. data/lib/active_merchant/billing/gateways/s5.rb +226 -0
  166. data/lib/active_merchant/billing/gateways/sage.rb +173 -0
  167. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +89 -0
  168. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +115 -0
  169. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  170. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  171. data/lib/active_merchant/billing/gateways/sage_pay.rb +399 -0
  172. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  173. data/lib/active_merchant/billing/gateways/secure_net.rb +263 -0
  174. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  175. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  176. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  177. data/lib/active_merchant/billing/gateways/skip_jack.rb +451 -0
  178. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  179. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  180. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  181. data/lib/active_merchant/billing/gateways/stripe.rb +489 -0
  182. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  183. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  184. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  185. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  186. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  187. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  188. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  189. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  190. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +259 -0
  191. data/lib/active_merchant/billing/gateways/vanco.rb +280 -0
  192. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  193. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  194. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  195. data/lib/active_merchant/billing/gateways/wepay.rb +205 -0
  196. data/lib/active_merchant/billing/gateways/wirecard.rb +420 -0
  197. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  198. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +204 -0
  199. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  200. data/lib/active_merchant/billing/model.rb +30 -0
  201. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +24 -0
  202. data/lib/active_merchant/billing/payment_token.rb +21 -0
  203. data/lib/active_merchant/billing/rails.rb +3 -0
  204. data/lib/active_merchant/billing/response.rb +92 -0
  205. data/lib/active_merchant/connection.rb +172 -0
  206. data/lib/active_merchant/country.rb +332 -0
  207. data/lib/active_merchant/empty.rb +20 -0
  208. data/lib/active_merchant/errors.rb +35 -0
  209. data/lib/active_merchant/network_connection_retries.rb +79 -0
  210. data/lib/active_merchant/post_data.rb +24 -0
  211. data/lib/active_merchant/posts_data.rb +84 -0
  212. data/lib/active_merchant/version.rb +3 -0
  213. data/lib/activemerchant.rb +1 -0
  214. data/lib/certs/cacert.pem +3866 -0
  215. data/lib/support/gateway_support.rb +71 -0
  216. data/lib/support/outbound_hosts.rb +28 -0
  217. data/lib/support/ssl_verify.rb +93 -0
  218. metadata +387 -0
@@ -0,0 +1,326 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # The Mercury gateway integration by default requires that the Mercury
4
+ # account being used has tokenization turned. This enables the use of
5
+ # capture/refund/void without having to pass the credit card back in each
6
+ # time. Only the "OneTime" tokenization is used; there is no use of
7
+ # "Recurring" tokenization.
8
+ #
9
+ # If you don't wish to enable Mercury tokenization, you can pass
10
+ # <code>:tokenization => false</code> as an option when creating the
11
+ # gateway. If you do so, then passing a +:credit_card+ option to +capture+
12
+ # and +refund+ will become mandatory.
13
+ class MercuryGateway < Gateway
14
+ URLS = {
15
+ :test => 'https://w1.mercurydev.net/ws/ws.asmx',
16
+ :live => 'https://w1.mercurypay.com/ws/ws.asmx'
17
+ }
18
+
19
+ self.homepage_url = 'http://www.mercurypay.com'
20
+ self.display_name = 'Mercury'
21
+ self.supported_countries = ['US','CA']
22
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
23
+ self.default_currency = 'USD'
24
+
25
+ STANDARD_ERROR_CODE_MAPPING = {
26
+ '100204' => STANDARD_ERROR_CODE[:invalid_number],
27
+ '100205' => STANDARD_ERROR_CODE[:invalid_expiry_date],
28
+ '000000' => STANDARD_ERROR_CODE[:card_declined]
29
+ }
30
+
31
+ def initialize(options = {})
32
+ requires!(options, :login, :password)
33
+ @use_tokenization = (!options.has_key?(:tokenization) || options[:tokenization])
34
+ super
35
+ end
36
+
37
+ def purchase(money, credit_card, options = {})
38
+ requires!(options, :order_id)
39
+
40
+ request = build_non_authorized_request('Sale', money, credit_card, options)
41
+ commit('Sale', request)
42
+ end
43
+
44
+ def credit(money, credit_card, options = {})
45
+ requires!(options, :order_id)
46
+
47
+ request = build_non_authorized_request('Return', money, credit_card, options)
48
+ commit('Return', request)
49
+ end
50
+
51
+ def authorize(money, credit_card, options = {})
52
+ requires!(options, :order_id)
53
+
54
+ request = build_non_authorized_request('PreAuth', money, credit_card, options.merge(:authorized => money))
55
+ commit('PreAuth', request)
56
+ end
57
+
58
+ def capture(money, authorization, options = {})
59
+ requires!(options, :credit_card) unless @use_tokenization
60
+
61
+ request = build_authorized_request('PreAuthCapture', money, authorization, options[:credit_card], options.merge(:authorized => money))
62
+ commit('PreAuthCapture', request)
63
+ end
64
+
65
+ def refund(money, authorization, options = {})
66
+ requires!(options, :credit_card) unless @use_tokenization
67
+
68
+ request = build_authorized_request('Return', money, authorization, options[:credit_card], options)
69
+ commit('Return', request)
70
+ end
71
+
72
+ def void(authorization, options={})
73
+ requires!(options, :credit_card) unless @use_tokenization
74
+
75
+ request = build_authorized_request('VoidSale', nil, authorization, options[:credit_card], options)
76
+ commit('VoidSale', request)
77
+ end
78
+
79
+ def store(credit_card, options={})
80
+ request = build_card_lookup_request(credit_card, options)
81
+ commit('CardLookup', request)
82
+ end
83
+
84
+ private
85
+
86
+ def build_non_authorized_request(action, money, credit_card, options)
87
+ xml = Builder::XmlMarkup.new
88
+
89
+ xml.tag! "TStream" do
90
+ xml.tag! "Transaction" do
91
+ xml.tag! 'TranType', 'Credit'
92
+ xml.tag! 'TranCode', action
93
+ if action == 'PreAuth' || action == 'Sale'
94
+ xml.tag! "PartialAuth", "Allow"
95
+ end
96
+ add_invoice(xml, options[:order_id], nil, options)
97
+ add_reference(xml, "RecordNumberRequested")
98
+ add_customer_data(xml, options)
99
+ add_amount(xml, money, options)
100
+ add_credit_card(xml, credit_card, action)
101
+ add_address(xml, options) unless credit_card.track_data.present?
102
+ end
103
+ end
104
+ xml = xml.target!
105
+ end
106
+
107
+ def build_authorized_request(action, money, authorization, credit_card, options)
108
+ xml = Builder::XmlMarkup.new
109
+
110
+ invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount = split_authorization(authorization)
111
+ ref_no = "1" if ref_no.blank?
112
+
113
+ xml.tag! "TStream" do
114
+ xml.tag! "Transaction" do
115
+ xml.tag! 'TranType', 'Credit'
116
+ if action == 'PreAuthCapture'
117
+ xml.tag! "PartialAuth", "Allow"
118
+ end
119
+ xml.tag! 'TranCode', (@use_tokenization ? (action + "ByRecordNo") : action)
120
+ add_invoice(xml, invoice_no, ref_no, options)
121
+ add_reference(xml, record_no)
122
+ add_customer_data(xml, options)
123
+ add_amount(xml, (money || amount.to_i), options)
124
+ add_credit_card(xml, credit_card, action) if credit_card
125
+ add_address(xml, options)
126
+ xml.tag! 'TranInfo' do
127
+ xml.tag! "AuthCode", auth_code
128
+ xml.tag! "AcqRefData", acq_ref_data
129
+ xml.tag! "ProcessData", process_data
130
+ end
131
+ end
132
+ end
133
+ xml = xml.target!
134
+ end
135
+
136
+ def build_card_lookup_request(credit_card, options)
137
+ xml = Builder::XmlMarkup.new
138
+
139
+ xml.tag! "TStream" do
140
+ xml.tag! "Transaction" do
141
+ xml.tag! 'TranType', 'CardLookup'
142
+ xml.tag! 'RecordNo', 'RecordNumberRequested'
143
+ xml.tag! 'Frequency', 'OneTime'
144
+
145
+ xml.tag! 'Memo', options[:description]
146
+ add_customer_data(xml, options)
147
+ add_credit_card(xml, credit_card, options)
148
+ end
149
+ end
150
+ xml.target!
151
+ end
152
+
153
+ def add_invoice(xml, invoice_no, ref_no, options)
154
+ xml.tag! 'InvoiceNo', invoice_no
155
+ xml.tag! 'RefNo', (ref_no || invoice_no)
156
+ xml.tag! 'OperatorID', options[:merchant] if options[:merchant]
157
+ xml.tag! 'Memo', options[:description] if options[:description]
158
+ end
159
+
160
+ def add_reference(xml, record_no)
161
+ if @use_tokenization
162
+ xml.tag! "Frequency", "OneTime"
163
+ xml.tag! "RecordNo", record_no
164
+ end
165
+ end
166
+
167
+ def add_customer_data(xml, options)
168
+ xml.tag! 'IpAddress', options[:ip] if options[:ip]
169
+ if options[:customer]
170
+ xml.tag! "TranInfo" do
171
+ xml.tag! 'CustomerCode', options[:customer]
172
+ end
173
+ end
174
+ xml.tag! 'MerchantID', @options[:login]
175
+ end
176
+
177
+ def add_amount(xml, money, options = {})
178
+ xml.tag! 'Amount' do
179
+ xml.tag! 'Purchase', amount(money)
180
+ xml.tag! 'Tax', options[:tax] if options[:tax]
181
+ xml.tag! 'Authorize', amount(options[:authorized]) if options[:authorized]
182
+ xml.tag! 'Gratuity', amount(options[:tip]) if options[:tip]
183
+ end
184
+ end
185
+
186
+ CARD_CODES = {
187
+ 'visa' => 'VISA',
188
+ 'master' => 'M/C',
189
+ 'american_express' => 'AMEX',
190
+ 'discover' => 'DCVR',
191
+ 'diners_club' => 'DCLB',
192
+ 'jcb' => 'JCB'
193
+ }
194
+
195
+ def add_credit_card(xml, credit_card, action)
196
+ xml.tag! 'Account' do
197
+ if credit_card.track_data.present?
198
+ xml.tag! 'Track1', credit_card.track_data
199
+ else
200
+ xml.tag! 'AcctNo', credit_card.number
201
+ xml.tag! 'ExpDate', expdate(credit_card)
202
+ end
203
+ end
204
+ xml.tag! 'CardType', CARD_CODES[credit_card.brand] if credit_card.brand
205
+
206
+ include_cvv = !%w(Return PreAuthCapture).include?(action) && !credit_card.track_data.present?
207
+ xml.tag! 'CVVData', credit_card.verification_value if(include_cvv && credit_card.verification_value)
208
+ end
209
+
210
+ def add_address(xml, options)
211
+ if billing_address = options[:billing_address] || options[:address]
212
+ xml.tag! 'AVS' do
213
+ xml.tag! 'Address', billing_address[:address1]
214
+ xml.tag! 'Zip', billing_address[:zip]
215
+ end
216
+ end
217
+ end
218
+
219
+ def parse(action, body)
220
+ response = {}
221
+ hashify_xml!(unescape_xml(body), response)
222
+ response
223
+ end
224
+
225
+ def hashify_xml!(xml, response)
226
+ xml = REXML::Document.new(xml)
227
+
228
+ xml.elements.each("//CmdResponse/*") do |node|
229
+ response[node.name.underscore.to_sym] = node.text
230
+ end
231
+
232
+ xml.elements.each("//TranResponse/*") do |node|
233
+ if node.name.to_s == "Amount"
234
+ node.elements.each do |amt|
235
+ response[amt.name.underscore.to_sym] = amt.text
236
+ end
237
+ else
238
+ response[node.name.underscore.to_sym] = node.text
239
+ end
240
+ end
241
+ end
242
+
243
+ def endpoint_url
244
+ URLS[test? ? :test : :live]
245
+ end
246
+
247
+ def build_soap_request(body)
248
+ xml = Builder::XmlMarkup.new
249
+
250
+ xml.instruct!
251
+ xml.tag! 'soap:Envelope', ENVELOPE_NAMESPACES do
252
+ xml.tag! 'soap:Body' do
253
+ xml.tag! 'CreditTransaction', 'xmlns' => homepage_url do
254
+ xml.tag! 'tran' do
255
+ xml << escape_xml(body)
256
+ end
257
+ xml.tag! 'pw', @options[:password]
258
+ end
259
+ end
260
+ end
261
+ xml.target!
262
+ end
263
+
264
+ def build_header
265
+ {
266
+ "SOAPAction" => "http://www.mercurypay.com/CreditTransaction",
267
+ "Content-Type" => "text/xml; charset=utf-8"
268
+ }
269
+ end
270
+
271
+ SUCCESS_CODES = [ 'Approved', 'Success' ]
272
+
273
+ def commit(action, request)
274
+ response = parse(action, ssl_post(endpoint_url, build_soap_request(request), build_header))
275
+
276
+ success = SUCCESS_CODES.include?(response[:cmd_status])
277
+ message = success ? 'Success' : message_from(response)
278
+
279
+ Response.new(success, message, response,
280
+ :test => test?,
281
+ :authorization => authorization_from(response),
282
+ :avs_result => { :code => response[:avs_result] },
283
+ :cvv_result => response[:cvv_result],
284
+ :error_code => success ? nil : STANDARD_ERROR_CODE_MAPPING[response[:dsix_return_code]])
285
+ end
286
+
287
+ def message_from(response)
288
+ response[:text_response]
289
+ end
290
+
291
+ def authorization_from(response)
292
+ dollars, cents = (response[:purchase] || "").split(".").collect{|e| e.to_i}
293
+ dollars ||= 0
294
+ cents ||= 0
295
+ [
296
+ response[:invoice_no],
297
+ response[:ref_no],
298
+ response[:auth_code],
299
+ response[:acq_ref_data],
300
+ response[:process_data],
301
+ response[:record_no],
302
+ ((dollars * 100) + cents).to_s
303
+ ].join(";")
304
+ end
305
+
306
+ def split_authorization(authorization)
307
+ invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount = authorization.split(";")
308
+ [invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount]
309
+ end
310
+
311
+ ENVELOPE_NAMESPACES = {
312
+ 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
313
+ 'xmlns:soap' => "http://schemas.xmlsoap.org/soap/envelope/",
314
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
315
+ }
316
+
317
+ def escape_xml(xml)
318
+ "\n<![CDATA[\n#{xml}\n]]>\n"
319
+ end
320
+
321
+ def unescape_xml(escaped_xml)
322
+ escaped_xml.gsub(/\&gt;/,'>').gsub(/\&lt;/,'<')
323
+ end
324
+ end
325
+ end
326
+ end
@@ -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