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,319 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class MerchantWareGateway < Gateway
4
+ class_attribute :v4_live_url
5
+
6
+ self.live_url = self.test_url = 'https://ps1.merchantware.net/MerchantWARE/ws/RetailTransaction/TXRetail.asmx'
7
+ self.v4_live_url = 'https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx'
8
+
9
+ self.supported_countries = ['US']
10
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
11
+ self.homepage_url = 'http://merchantwarehouse.com/merchantware'
12
+ self.display_name = 'MerchantWARE'
13
+
14
+ ENV_NAMESPACES = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
15
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
16
+ "xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/"
17
+ }
18
+ ENV_NAMESPACES_V4 = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
19
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
20
+ "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/"
21
+ }
22
+
23
+ TX_NAMESPACE = "http://merchantwarehouse.com/MerchantWARE/Client/TransactionRetail"
24
+ TX_NAMESPACE_V4 = "http://schemas.merchantwarehouse.com/merchantware/40/Credit/"
25
+
26
+ ACTIONS = {
27
+ :purchase => "IssueKeyedSale",
28
+ :authorize => "IssueKeyedPreAuth",
29
+ :capture => "IssuePostAuth",
30
+ :void => "VoidPreAuthorization",
31
+ :credit => "IssueKeyedRefund",
32
+ :reference_credit => "IssueRefundByReference"
33
+ }
34
+
35
+ # Creates a new MerchantWareGateway
36
+ #
37
+ # The gateway requires that a valid login, password, and name be passed
38
+ # in the +options+ hash.
39
+ #
40
+ # ==== Options
41
+ #
42
+ # * <tt>:login</tt> - The MerchantWARE SiteID.
43
+ # * <tt>:password</tt> - The MerchantWARE Key.
44
+ # * <tt>:name</tt> - The MerchantWARE Name.
45
+ def initialize(options = {})
46
+ requires!(options, :login, :password, :name)
47
+ super
48
+ end
49
+
50
+ # Authorize a credit card for a given amount.
51
+ #
52
+ # ==== Parameters
53
+ # * <tt>money</tt> - The amount to be authorized as an Integer value in cents.
54
+ # * <tt>credit_card</tt> - The CreditCard details for the transaction.
55
+ # * <tt>options</tt>
56
+ # * <tt>:order_id</tt> - A unique reference for this order (required).
57
+ # * <tt>:billing_address</tt> - The billing address for the cardholder.
58
+ def authorize(money, credit_card, options = {})
59
+ request = build_purchase_request(:authorize, money, credit_card, options)
60
+ commit(:authorize, request)
61
+ end
62
+
63
+ # Authorize and immediately capture funds from a credit card.
64
+ #
65
+ # ==== Parameters
66
+ # * <tt>money</tt> - The amount to be authorized as anInteger value in cents.
67
+ # * <tt>credit_card</tt> - The CreditCard details for the transaction.
68
+ # * <tt>options</tt>
69
+ # * <tt>:order_id</tt> - A unique reference for this order (required).
70
+ # * <tt>:billing_address</tt> - The billing address for the cardholder.
71
+ def purchase(money, credit_card, options = {})
72
+ request = build_purchase_request(:purchase, money, credit_card, options)
73
+ commit(:purchase, request)
74
+ end
75
+
76
+ # Capture authorized funds from a credit card.
77
+ #
78
+ # ==== Parameters
79
+ # * <tt>money</tt> - The amount to be captured as anInteger value in cents.
80
+ # * <tt>authorization</tt> - The authorization string returned from the initial authorization.
81
+ def capture(money, authorization, options = {})
82
+ request = build_capture_request(:capture, money, authorization, options)
83
+ commit(:capture, request)
84
+ end
85
+
86
+ # Void a transaction.
87
+ #
88
+ # ==== Parameters
89
+ # * <tt>authorization</tt> - The authorization string returned from the initial authorization or purchase.
90
+ def void(authorization, options = {})
91
+ reference, options[:order_id] = split_reference(authorization)
92
+ request = v4_soap_request(:void) do |xml|
93
+ add_reference_token(xml, reference)
94
+ end
95
+ commit(:void, request, true)
96
+ end
97
+
98
+ # Refund an amount back a cardholder
99
+ #
100
+ # ==== Parameters
101
+ #
102
+ # * <tt>money</tt> - The amount to be refunded as an Integer value in cents.
103
+ # * <tt>identification</tt> - The credit card you want to refund or the authorization for the existing transaction you are refunding.
104
+ # * <tt>options</tt>
105
+ # * <tt>:order_id</tt> - A unique reference for this order (required when performing a non-referenced credit)
106
+ def credit(money, identification, options = {})
107
+ if identification.is_a?(String)
108
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
109
+ refund(money, identification, options)
110
+ else
111
+ perform_credit(money, identification, options)
112
+ end
113
+ end
114
+
115
+ def refund(money, reference, options = {})
116
+ perform_reference_credit(money, reference, options)
117
+ end
118
+
119
+ private
120
+
121
+ def soap_request(action)
122
+ xml = Builder::XmlMarkup.new :indent => 2
123
+ xml.instruct!
124
+ xml.tag! "env:Envelope", ENV_NAMESPACES do
125
+ xml.tag! "env:Body" do
126
+ xml.tag! ACTIONS[action], "xmlns" => TX_NAMESPACE do
127
+ add_credentials(xml)
128
+ yield xml
129
+ end
130
+ end
131
+ end
132
+ xml.target!
133
+ end
134
+
135
+ def v4_soap_request(action)
136
+ xml = Builder::XmlMarkup.new :indent => 2
137
+ xml.instruct!
138
+ xml.tag! "soap:Envelope", ENV_NAMESPACES_V4 do
139
+ xml.tag! "soap:Body" do
140
+ xml.tag! ACTIONS[:void], "xmlns" => TX_NAMESPACE_V4 do
141
+ xml.tag! "merchantName", @options[:name]
142
+ xml.tag! "merchantSiteId", @options[:login]
143
+ xml.tag! "merchantKey", @options[:password]
144
+ yield xml
145
+ end
146
+ end
147
+ end
148
+ xml.target!
149
+ end
150
+
151
+ def build_purchase_request(action, money, credit_card, options)
152
+ requires!(options, :order_id)
153
+
154
+ soap_request(action) do |xml|
155
+ add_invoice(xml, options)
156
+ add_amount(xml, money)
157
+ add_credit_card(xml, credit_card)
158
+ add_address(xml, options)
159
+ end
160
+ end
161
+
162
+ def build_capture_request(action, money, identification, options)
163
+ reference, options[:order_id] = split_reference(identification)
164
+
165
+ soap_request(action) do |xml|
166
+ add_reference(xml, reference)
167
+ add_invoice(xml, options)
168
+ add_amount(xml, money)
169
+ end
170
+ end
171
+
172
+ def perform_reference_credit(money, identification, options)
173
+ reference, options[:order_id] = split_reference(identification)
174
+
175
+ request = soap_request(:reference_credit) do |xml|
176
+ add_reference(xml, reference)
177
+ add_invoice(xml, options)
178
+ add_amount(xml, money, "strOverrideAmount")
179
+ end
180
+
181
+ commit(:reference_credit, request)
182
+ end
183
+
184
+ def perform_credit(money, credit_card, options)
185
+ requires!(options, :order_id)
186
+
187
+ request = soap_request(:credit) do |xml|
188
+ add_invoice(xml, options)
189
+ add_amount(xml, money)
190
+ add_credit_card(xml, credit_card)
191
+ end
192
+
193
+ commit(:credit, request)
194
+ end
195
+
196
+ def add_credentials(xml)
197
+ xml.tag! "strSiteId", @options[:login]
198
+ xml.tag! "strKey", @options[:password]
199
+ xml.tag! "strName", @options[:name]
200
+ end
201
+
202
+ def add_invoice(xml, options)
203
+ xml.tag! "strOrderNumber", options[:order_id].to_s.gsub(/[^\w]/, '').slice(0, 25)
204
+ end
205
+
206
+ def add_amount(xml, money, tag = "strAmount")
207
+ xml.tag! tag, amount(money)
208
+ end
209
+
210
+ def add_reference(xml, reference)
211
+ xml.tag! "strReferenceCode", reference
212
+ end
213
+
214
+ def add_reference_token(xml, reference)
215
+ xml.tag! "token", reference
216
+ end
217
+
218
+ def add_address(xml, options)
219
+ if address = options[:billing_address] || options[:address]
220
+ xml.tag! "strAVSStreetAddress", address[:address1]
221
+ xml.tag! "strAVSZipCode", address[:zip]
222
+ end
223
+ end
224
+
225
+ def add_credit_card(xml, credit_card)
226
+ if credit_card.respond_to?(:track_data) && credit_card.track_data.present?
227
+ xml.tag! "trackData", credit_card.track_data
228
+ else
229
+ xml.tag! "strPAN", credit_card.number
230
+ xml.tag! "strExpDate", expdate(credit_card)
231
+ xml.tag! "strCardHolder", credit_card.name
232
+ xml.tag! "strCVCode", credit_card.verification_value if credit_card.verification_value?
233
+ end
234
+ end
235
+
236
+ def split_reference(reference)
237
+ reference.to_s.split(";")
238
+ end
239
+
240
+ def parse(action, data)
241
+ response = {}
242
+ xml = REXML::Document.new(data)
243
+
244
+ root = REXML::XPath.first(xml, "//#{ACTIONS[action]}Response/#{ACTIONS[action]}Result")
245
+
246
+ root.elements.each do |element|
247
+ response[element.name] = element.text
248
+ end
249
+
250
+ status, code, message = response["ApprovalStatus"].split(";")
251
+ response[:status] = status
252
+
253
+ if response[:success] = status == "APPROVED"
254
+ response[:message] = status
255
+ else
256
+ response[:message] = message
257
+ response[:failure_code] = code
258
+ end
259
+
260
+ response
261
+ end
262
+
263
+ def parse_error(http_response)
264
+ response = {}
265
+ response[:http_code] = http_response.code
266
+ response[:http_message] = http_response.message
267
+ response[:success] = false
268
+
269
+ document = REXML::Document.new(http_response.body)
270
+
271
+ node = REXML::XPath.first(document, "//soap:Fault")
272
+
273
+ node.elements.each do |element|
274
+ response[element.name] = element.text
275
+ end
276
+
277
+ response[:message] = response["faultstring"].to_s.gsub("\n", " ")
278
+ response
279
+ rescue REXML::ParseException
280
+ response[:http_body] = http_response.body
281
+ response[:message] = "Failed to parse the failed response"
282
+ response
283
+ end
284
+
285
+ def soap_action(action, v4 = false)
286
+ v4 ? "#{TX_NAMESPACE_V4}#{ACTIONS[action]}" : "#{TX_NAMESPACE}/#{ACTIONS[action]}"
287
+ end
288
+
289
+ def url(v4 = false)
290
+ v4 ? v4_live_url : live_url
291
+ end
292
+
293
+ def commit(action, request, v4 = false)
294
+ begin
295
+ data = ssl_post(url(v4), request,
296
+ "Content-Type" => 'text/xml; charset=utf-8',
297
+ "SOAPAction" => soap_action(action, v4)
298
+ )
299
+ response = parse(action, data)
300
+ rescue ActiveMerchant::ResponseError => e
301
+ response = parse_error(e.response)
302
+ end
303
+
304
+ Response.new(response[:success], response[:message], response,
305
+ :test => test?,
306
+ :authorization => authorization_from(response),
307
+ :avs_result => { :code => response["AVSResponse"] },
308
+ :cvv_result => response["CVResponse"]
309
+ )
310
+ end
311
+
312
+ def authorization_from(response)
313
+ if response[:success]
314
+ [ response["ReferenceID"], response["OrderNumber"] ].join(";")
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,268 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class MerchantWareVersionFourGateway < Gateway
4
+ self.live_url = 'https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx'
5
+ self.test_url = 'https://staging.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx'
6
+
7
+ self.supported_countries = ['US']
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
9
+ self.homepage_url = 'http://merchantwarehouse.com/merchantware'
10
+ self.display_name = 'MerchantWARE'
11
+
12
+ ENV_NAMESPACES = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
13
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
14
+ "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/" }
15
+
16
+ TX_NAMESPACE = "http://schemas.merchantwarehouse.com/merchantware/40/Credit/"
17
+
18
+ ACTIONS = {
19
+ :purchase => "SaleKeyed",
20
+ :reference_purchase => 'RepeatSale',
21
+ :authorize => "PreAuthorizationKeyed",
22
+ :capture => "PostAuthorization",
23
+ :void => "VoidPreAuthorization",
24
+ :refund => "Refund"
25
+ }
26
+
27
+ # Creates a new MerchantWareVersionFourGateway
28
+ #
29
+ # The gateway requires that a valid login, password, and name be passed
30
+ # in the +options+ hash.
31
+ #
32
+ # ==== Options
33
+ #
34
+ # * <tt>:login</tt> - The MerchantWARE SiteID.
35
+ # * <tt>:password</tt> - The MerchantWARE Key.
36
+ # * <tt>:name</tt> - The MerchantWARE Name.
37
+ def initialize(options = {})
38
+ requires!(options, :login, :password, :name)
39
+ super
40
+ end
41
+
42
+ # Authorize a credit card for a given amount.
43
+ #
44
+ # ==== Parameters
45
+ # * <tt>money</tt> - The amount to be authorized as an Integer value in cents.
46
+ # * <tt>credit_card</tt> - The CreditCard details for the transaction.
47
+ # * <tt>options</tt>
48
+ # * <tt>:order_id</tt> - A unique reference for this order (required).
49
+ # * <tt>:billing_address</tt> - The billing address for the cardholder.
50
+ def authorize(money, credit_card, options = {})
51
+ request = build_purchase_request(:authorize, money, credit_card, options)
52
+ commit(:authorize, request)
53
+ end
54
+
55
+ # Authorize and immediately capture funds from a credit card.
56
+ #
57
+ # ==== Parameters
58
+ # * <tt>money</tt> - The amount to be authorized as anInteger value in cents.
59
+ # * <tt>payment_source</tt> - The CreditCard details or 'token' from prior transaction
60
+ # * <tt>options</tt>
61
+ # * <tt>:order_id</tt> - A unique reference for this order (required).
62
+ # * <tt>:billing_address</tt> - The billing address for the cardholder.
63
+ def purchase(money, payment_source, options = {})
64
+ action = payment_source.is_a?(String) ? :reference_purchase : :purchase
65
+ request = build_purchase_request(action, money, payment_source, options)
66
+ commit(action, request)
67
+ end
68
+
69
+ # Capture authorized funds from a credit card.
70
+ #
71
+ # ==== Parameters
72
+ # * <tt>money</tt> - The amount to be captured as anInteger value in cents.
73
+ # * <tt>authorization</tt> - The authorization string returned from the initial authorization.
74
+ def capture(money, authorization, options = {})
75
+ request = build_capture_request(:capture, money, authorization, options)
76
+ commit(:capture, request)
77
+ end
78
+
79
+ # Void a transaction.
80
+ #
81
+ # ==== Parameters
82
+ # * <tt>authorization</tt> - The authorization string returned from the initial authorization or purchase.
83
+ def void(authorization, options = {})
84
+ reference, options[:order_id] = split_reference(authorization)
85
+ request = soap_request(:void) do |xml|
86
+ add_reference_token(xml, reference)
87
+ end
88
+ commit(:void, request)
89
+ end
90
+
91
+ # Refund an amount back a cardholder
92
+ #
93
+ # ==== Parameters
94
+ #
95
+ # * <tt>money</tt> - The amount to be refunded as an Integer value in cents.
96
+ # * <tt>identification</tt> - The credit card you want to refund or the authorization for the existing transaction you are refunding.
97
+ # * <tt>options</tt>
98
+ # * <tt>:order_id</tt> - A unique reference for this order (required when performing a non-referenced credit)
99
+ def refund(money, identification, options = {})
100
+ reference, options[:order_id] = split_reference(identification)
101
+
102
+ request = soap_request(:refund) do |xml|
103
+ add_reference_token(xml, reference)
104
+ add_invoice(xml, options)
105
+ add_amount(xml, money, "overrideAmount")
106
+ end
107
+
108
+ commit(:refund, request)
109
+ end
110
+
111
+ private
112
+
113
+ def soap_request(action)
114
+ xml = Builder::XmlMarkup.new :indent => 2
115
+ xml.instruct!
116
+ xml.tag! "soap:Envelope", ENV_NAMESPACES do
117
+ xml.tag! "soap:Body" do
118
+ xml.tag! ACTIONS[action], "xmlns" => TX_NAMESPACE do
119
+ xml.tag! "merchantName", @options[:name]
120
+ xml.tag! "merchantSiteId", @options[:login]
121
+ xml.tag! "merchantKey", @options[:password]
122
+ yield xml
123
+ end
124
+ end
125
+ end
126
+ xml.target!
127
+ end
128
+
129
+ def build_purchase_request(action, money, payment_source, options)
130
+ requires!(options, :order_id)
131
+
132
+ soap_request(action) do |xml|
133
+ add_invoice(xml, options)
134
+ add_amount(xml, money)
135
+ add_payment_source(xml, payment_source)
136
+ add_address(xml, options)
137
+ end
138
+ end
139
+
140
+ def build_capture_request(action, money, identification, options)
141
+ reference, options[:order_id] = split_reference(identification)
142
+
143
+ soap_request(action) do |xml|
144
+ add_reference_token(xml, reference)
145
+ add_invoice(xml, options)
146
+ add_amount(xml, money)
147
+ end
148
+ end
149
+
150
+ def add_invoice(xml, options)
151
+ xml.tag! "invoiceNumber", options[:order_id].to_s.gsub(/[^\w]/, '').slice(0, 25)
152
+ end
153
+
154
+ def add_amount(xml, money, tag = "amount")
155
+ xml.tag! tag, amount(money)
156
+ end
157
+
158
+ def add_reference_token(xml, reference)
159
+ xml.tag! "token", reference
160
+ end
161
+
162
+ def add_address(xml, options)
163
+ address = options[:billing_address] || options[:address] || {}
164
+ xml.tag! "avsStreetAddress", address[:address1]
165
+ xml.tag! "avsStreetZipCode", address[:zip]
166
+ end
167
+
168
+ def add_payment_source(xml, source)
169
+ if source.is_a?(String)
170
+ add_reference_token(xml, source)
171
+ else
172
+ add_credit_card(xml, source)
173
+ end
174
+ end
175
+
176
+ def add_credit_card(xml, credit_card)
177
+ xml.tag! "cardNumber", credit_card.number
178
+ xml.tag! "expirationDate", expdate(credit_card)
179
+ xml.tag! "cardholder", credit_card.name
180
+ xml.tag! "cardSecurityCode", credit_card.verification_value if credit_card.verification_value?
181
+ end
182
+
183
+ def split_reference(reference)
184
+ reference.to_s.split(";")
185
+ end
186
+
187
+ def parse(action, data)
188
+ response = {}
189
+ xml = REXML::Document.new(data)
190
+
191
+ root = REXML::XPath.first(xml, "//#{ACTIONS[action]}Response/#{ACTIONS[action]}Result")
192
+
193
+ root.elements.each do |element|
194
+ response[element.name] = element.text
195
+ end
196
+
197
+ if response["ErrorMessage"].present?
198
+ response[:message] = response["ErrorMessage"]
199
+ response[:success] = false
200
+ else
201
+ status, code, message = response["ApprovalStatus"].split(";")
202
+ response[:status] = status
203
+
204
+ if response[:success] = status == "APPROVED"
205
+ response[:message] = status
206
+ else
207
+ response[:message] = message
208
+ response[:failure_code] = code
209
+ end
210
+ end
211
+
212
+ response
213
+ end
214
+
215
+ def parse_error(http_response, action)
216
+ response = {}
217
+ response[:http_code] = http_response.code
218
+ response[:http_message] = http_response.message
219
+ response[:success] = false
220
+
221
+ document = REXML::Document.new(http_response.body)
222
+ node = REXML::XPath.first(document, "//#{ACTIONS[action]}Response/#{ACTIONS[action]}Result")
223
+
224
+ node.elements.each do |element|
225
+ response[element.name] = element.text
226
+ end
227
+
228
+ response[:message] = response["ErrorMessage"].to_s.gsub("\n", " ")
229
+ response
230
+ rescue REXML::ParseException
231
+ response[:http_body] = http_response.body
232
+ response[:message] = "Failed to parse the failed response"
233
+ response
234
+ end
235
+
236
+ def soap_action(action)
237
+ "#{TX_NAMESPACE}#{ACTIONS[action]}"
238
+ end
239
+
240
+ def url
241
+ test? ? test_url : live_url
242
+ end
243
+
244
+ def commit(action, request)
245
+ begin
246
+ data = ssl_post(url, request,
247
+ "Content-Type" => 'text/xml; charset=utf-8',
248
+ "SOAPAction" => soap_action(action)
249
+ )
250
+ response = parse(action, data)
251
+ rescue ActiveMerchant::ResponseError => e
252
+ response = parse_error(e.response, action)
253
+ end
254
+
255
+ Response.new(response[:success], response[:message], response,
256
+ :test => test?,
257
+ :authorization => authorization_from(response),
258
+ :avs_result => { :code => response["AvsResponse"] },
259
+ :cvv_result => response["CvResponse"]
260
+ )
261
+ end
262
+
263
+ def authorization_from(response)
264
+ response['Token']
265
+ end
266
+ end
267
+ end
268
+ end