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,331 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class WorldpayGateway < Gateway
4
+ self.test_url = 'https://secure-test.worldpay.com/jsp/merchant/xml/paymentService.jsp'
5
+ self.live_url = 'https://secure.worldpay.com/jsp/merchant/xml/paymentService.jsp'
6
+
7
+ self.default_currency = 'GBP'
8
+ self.money_format = :cents
9
+ self.supported_countries = %w(HK US GB AU AD BE CH CY CZ DE DK ES FI FR GI GR HU IE IL IT LI LU MC MT NL NO NZ PL PT SE SG SI SM TR UM VA)
10
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :laser, :switch]
11
+ self.homepage_url = 'http://www.worldpay.com/'
12
+ self.display_name = 'Worldpay'
13
+
14
+ CARD_CODES = {
15
+ 'visa' => 'VISA-SSL',
16
+ 'master' => 'ECMC-SSL',
17
+ 'discover' => 'DISCOVER-SSL',
18
+ 'american_express' => 'AMEX-SSL',
19
+ 'jcb' => 'JCB-SSL',
20
+ 'maestro' => 'MAESTRO-SSL',
21
+ 'laser' => 'LASER-SSL',
22
+ 'diners_club' => 'DINERS-SSL',
23
+ 'switch' => 'MAESTRO-SSL'
24
+ }
25
+
26
+ def initialize(options = {})
27
+ requires!(options, :login, :password)
28
+ super
29
+ end
30
+
31
+ def purchase(money, payment_method, options = {})
32
+ MultiResponse.run do |r|
33
+ r.process{authorize(money, payment_method, options)}
34
+ r.process{capture(money, r.authorization, options.merge(:authorization_validated => true))}
35
+ end
36
+ end
37
+
38
+ def authorize(money, payment_method, options = {})
39
+ requires!(options, :order_id)
40
+ authorize_request(money, payment_method, options)
41
+ end
42
+
43
+ def capture(money, authorization, options = {})
44
+ MultiResponse.run do |r|
45
+ r.process{inquire_request(authorization, options, "AUTHORISED")} unless options[:authorization_validated]
46
+ if r.params
47
+ authorization_currency = r.params['amount_currency_code']
48
+ options = options.merge(:currency => authorization_currency) if authorization_currency.present?
49
+ end
50
+ r.process{capture_request(money, authorization, options)}
51
+ end
52
+ end
53
+
54
+ def void(authorization, options = {})
55
+ MultiResponse.run do |r|
56
+ r.process{inquire_request(authorization, options, "AUTHORISED")}
57
+ r.process{cancel_request(authorization, options)}
58
+ end
59
+ end
60
+
61
+ def refund(money, authorization, options = {})
62
+ MultiResponse.run do |r|
63
+ r.process{inquire_request(authorization, options, "CAPTURED", "SETTLED", "SETTLED_BY_MERCHANT")}
64
+ r.process{refund_request(money, authorization, options)}
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def authorize_request(money, payment_method, options)
71
+ commit('authorize', build_authorization_request(money, payment_method, options), "AUTHORISED")
72
+ end
73
+
74
+ def capture_request(money, authorization, options)
75
+ commit('capture', build_capture_request(money, authorization, options), :ok)
76
+ end
77
+
78
+ def cancel_request(authorization, options)
79
+ commit('cancel', build_void_request(authorization, options), :ok)
80
+ end
81
+
82
+ def inquire_request(authorization, options, *success_criteria)
83
+ commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria)
84
+ end
85
+
86
+ def refund_request(money, authorization, options)
87
+ commit('refund', build_refund_request(money, authorization, options), :ok)
88
+ end
89
+
90
+ def build_request
91
+ xml = Builder::XmlMarkup.new :indent => 2
92
+ xml.instruct! :xml, :encoding => 'UTF-8'
93
+ xml.declare! :DOCTYPE, :paymentService, :PUBLIC, "-//WorldPay//DTD WorldPay PaymentService v1//EN", "http://dtd.worldpay.com/paymentService_v1.dtd"
94
+ xml.tag! 'paymentService', 'version' => "1.4", 'merchantCode' => @options[:login] do
95
+ yield xml
96
+ end
97
+ xml.target!
98
+ end
99
+
100
+ def build_order_modify_request(authorization)
101
+ build_request do |xml|
102
+ xml.tag! 'modify' do
103
+ xml.tag! 'orderModification', 'orderCode' => authorization do
104
+ yield xml
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def build_order_inquiry_request(authorization, options)
111
+ build_request do |xml|
112
+ xml.tag! 'inquiry' do
113
+ xml.tag! 'orderInquiry', 'orderCode' => authorization
114
+ end
115
+ end
116
+ end
117
+
118
+ def build_authorization_request(money, payment_method, options)
119
+ build_request do |xml|
120
+ xml.tag! 'submit' do
121
+ xml.tag! 'order', {'orderCode' => options[:order_id], 'installationId' => @options[:inst_id]}.reject{|_,v| !v} do
122
+ xml.description(options[:description].blank? ? "Purchase" : options[:description])
123
+ add_amount(xml, money, options)
124
+ if options[:order_content]
125
+ xml.tag! 'orderContent' do
126
+ xml.cdata! options[:order_content]
127
+ end
128
+ end
129
+ add_payment_method(xml, money, payment_method, options)
130
+ add_email(xml, options)
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ def build_capture_request(money, authorization, options)
137
+ build_order_modify_request(authorization) do |xml|
138
+ xml.tag! 'capture' do
139
+ time = Time.now
140
+ xml.tag! 'date', 'dayOfMonth' => time.day, 'month' => time.month, 'year'=> time.year
141
+ add_amount(xml, money, options)
142
+ end
143
+ end
144
+ end
145
+
146
+ def build_void_request(authorization, options)
147
+ build_order_modify_request(authorization) do |xml|
148
+ xml.tag! 'cancel'
149
+ end
150
+ end
151
+
152
+ def build_refund_request(money, authorization, options)
153
+ build_order_modify_request(authorization) do |xml|
154
+ xml.tag! 'refund' do
155
+ add_amount(xml, money, options.merge(:debit_credit_indicator => "credit"))
156
+ end
157
+ end
158
+ end
159
+
160
+ def add_amount(xml, money, options)
161
+ currency = options[:currency] || currency(money)
162
+ amount = localized_amount(money, currency)
163
+
164
+ amount_hash = {
165
+ :value => amount,
166
+ 'currencyCode' => currency,
167
+ 'exponent' => 2
168
+ }
169
+
170
+ if options[:debit_credit_indicator]
171
+ amount_hash.merge!('debitCreditIndicator' => options[:debit_credit_indicator])
172
+ end
173
+
174
+ xml.tag! 'amount', amount_hash
175
+ end
176
+
177
+ def add_payment_method(xml, amount, payment_method, options)
178
+ if payment_method.is_a?(String)
179
+ if options[:merchant_code]
180
+ xml.tag! 'payAsOrder', 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
181
+ add_amount(xml, amount, options)
182
+ end
183
+ else
184
+ xml.tag! 'payAsOrder', 'orderCode' => payment_method do
185
+ add_amount(xml, amount, options)
186
+ end
187
+ end
188
+ else
189
+ xml.tag! 'paymentDetails' do
190
+ xml.tag! CARD_CODES[card_brand(payment_method)] do
191
+ xml.tag! 'cardNumber', payment_method.number
192
+ xml.tag! 'expiryDate' do
193
+ xml.tag! 'date', 'month' => format(payment_method.month, :two_digits), 'year' => format(payment_method.year, :four_digits)
194
+ end
195
+
196
+ xml.tag! 'cardHolderName', payment_method.name
197
+ xml.tag! 'cvc', payment_method.verification_value
198
+
199
+ add_address(xml, (options[:billing_address] || options[:address]))
200
+ end
201
+ if options[:ip]
202
+ xml.tag! 'session', 'shopperIPAddress' => options[:ip]
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ def add_email(xml, options)
209
+ return unless options[:email]
210
+ xml.tag! 'shopper' do
211
+ xml.tag! 'shopperEmailAddress', options[:email]
212
+ end
213
+ end
214
+
215
+ def add_address(xml, address)
216
+ address = address_with_defaults(address)
217
+
218
+ xml.tag! 'cardAddress' do
219
+ xml.tag! 'address' do
220
+ if m = /^\s*([^\s]+)\s+(.+)$/.match(address[:name])
221
+ xml.tag! 'firstName', m[1]
222
+ xml.tag! 'lastName', m[2]
223
+ end
224
+ xml.tag! 'address1', address[:address1]
225
+ xml.tag! 'address2', address[:address2] if address[:address2]
226
+ xml.tag! 'postalCode', address[:zip]
227
+ xml.tag! 'city', address[:city]
228
+ xml.tag! 'state', address[:state]
229
+ xml.tag! 'countryCode', address[:country]
230
+ xml.tag! 'telephoneNumber', address[:phone] if address[:phone]
231
+ end
232
+ end
233
+ end
234
+
235
+ def address_with_defaults(address)
236
+ address ||= {}
237
+ address.delete_if { |_, v| v.blank? }
238
+ address.reverse_merge!(default_address)
239
+ end
240
+
241
+ def default_address
242
+ {
243
+ address1: 'N/A',
244
+ zip: '0000',
245
+ city: 'N/A',
246
+ state: 'N/A',
247
+ country: 'US'
248
+ }
249
+ end
250
+
251
+ def parse(action, xml)
252
+ parse_element({:action => action}, REXML::Document.new(xml))
253
+ end
254
+
255
+ def parse_element(raw, node)
256
+ node.attributes.each do |k, v|
257
+ raw["#{node.name.underscore}_#{k.underscore}".to_sym] = v
258
+ end
259
+ if node.has_elements?
260
+ raw[node.name.underscore.to_sym] = true unless node.name.blank?
261
+ node.elements.each{|e| parse_element(raw, e) }
262
+ else
263
+ raw[node.name.underscore.to_sym] = node.text unless node.text.nil?
264
+ end
265
+ raw
266
+ end
267
+
268
+ def commit(action, request, *success_criteria)
269
+ xmr = ssl_post(url, request, 'Content-Type' => 'text/xml', 'Authorization' => encoded_credentials)
270
+ raw = parse(action, xmr)
271
+ success, message = success_and_message_from(raw, success_criteria)
272
+
273
+ Response.new(
274
+ success,
275
+ message,
276
+ raw,
277
+ :authorization => authorization_from(raw),
278
+ :test => test?)
279
+
280
+ rescue ActiveMerchant::ResponseError => e
281
+ if e.response.code.to_s == "401"
282
+ return Response.new(false, "Invalid credentials", {}, :test => test?)
283
+ else
284
+ raise e
285
+ end
286
+ end
287
+
288
+ def url
289
+ test? ? self.test_url : self.live_url
290
+ end
291
+
292
+ # success_criteria can be:
293
+ # - a string or an array of strings (if one of many responses)
294
+ # - An array of strings if one of many responses could be considered a
295
+ # success.
296
+ def success_and_message_from(raw, success_criteria)
297
+ success = (success_criteria.include?(raw[:last_event]) || raw[:ok].present?)
298
+ if success
299
+ message = "SUCCESS"
300
+ else
301
+ message = (raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria))
302
+ end
303
+
304
+ [ success, message ]
305
+ end
306
+
307
+ def required_status_message(raw, success_criteria)
308
+ if(!success_criteria.include?(raw[:last_event]))
309
+ "A transaction status of #{success_criteria.collect{|c| "'#{c}'"}.join(" or ")} is required."
310
+ end
311
+ end
312
+
313
+ def authorization_from(raw)
314
+ pair = raw.detect{|k,v| k.to_s =~ /_order_code$/}
315
+ (pair ? pair.last : nil)
316
+ end
317
+
318
+ def encoded_credentials
319
+ credentials = "#{@options[:login]}:#{@options[:password]}"
320
+ "Basic #{[credentials].pack('m').strip}"
321
+ end
322
+
323
+ def localized_amount(money, currency)
324
+ amount = amount(money)
325
+ return amount unless CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s)
326
+
327
+ amount.to_i / 100 * 100
328
+ end
329
+ end
330
+ end
331
+ end
@@ -0,0 +1,181 @@
1
+ require "nokogiri"
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class WorldpayUsGateway < Gateway
6
+ self.display_name = "Worldpay US"
7
+ self.homepage_url = "http://www.worldpay.com/us"
8
+
9
+ # No sandbox, just use test cards.
10
+ self.live_url = 'https://trans.worldpay.us/cgi-bin/process.cgi'
11
+
12
+ self.supported_countries = ['US']
13
+ self.default_currency = 'USD'
14
+ self.money_format = :dollars
15
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb]
16
+
17
+ def initialize(options={})
18
+ requires!(options, :acctid, :subid, :merchantpin)
19
+ super
20
+ end
21
+
22
+ def purchase(money, payment_method, options={})
23
+ post = {}
24
+ add_invoice(post, money, options)
25
+ add_payment_method(post, payment_method)
26
+ add_customer_data(post, options)
27
+
28
+ commit('purchase', post)
29
+ end
30
+
31
+ def authorize(money, payment, options={})
32
+ post = {}
33
+ add_invoice(post, money, options)
34
+ add_payment_method(post, payment)
35
+ add_customer_data(post, options)
36
+
37
+ commit('authorize', post)
38
+ end
39
+
40
+ def capture(amount, authorization, options={})
41
+ post = {}
42
+ add_invoice(post, amount, options)
43
+ add_reference(post, authorization)
44
+ add_customer_data(post, options)
45
+
46
+ commit('capture', post)
47
+ end
48
+
49
+ def refund(amount, authorization, options={})
50
+ post = {}
51
+ add_invoice(post, amount, options)
52
+ add_reference(post, authorization)
53
+ add_customer_data(post, options)
54
+
55
+ commit("refund", post)
56
+ end
57
+
58
+ def void(authorization, options={})
59
+ post = {}
60
+ add_reference(post, authorization)
61
+
62
+ commit('void', post)
63
+ end
64
+
65
+ def verify(credit_card, options={})
66
+ MultiResponse.run(:use_first_response) do |r|
67
+ r.process { authorize(100, credit_card, options) }
68
+ r.process(:ignore_result) { void(r.authorization, options) }
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def add_customer_data(post, options)
75
+ if(billing_address = (options[:billing_address] || options[:address]))
76
+ post[:ci_companyname] = billing_address[:company]
77
+ post[:ci_billaddr1] = billing_address[:address1]
78
+ post[:ci_billaddr2] = billing_address[:address2]
79
+ post[:ci_billcity] = billing_address[:city]
80
+ post[:ci_billstate] = billing_address[:state]
81
+ post[:ci_billzip] = billing_address[:zip]
82
+ post[:ci_billcountry] = billing_address[:country]
83
+
84
+ post[:ci_phone] = billing_address[:phone]
85
+ post[:ci_email] = billing_address[:email]
86
+ post[:ci_ipaddress] = billing_address[:ip]
87
+ end
88
+
89
+ if(shipping_address = options[:shipping_address])
90
+ post[:ci_shipaddr1] = shipping_address[:address1]
91
+ post[:ci_shipaddr2] = shipping_address[:address2]
92
+ post[:ci_shipcity] = shipping_address[:city]
93
+ post[:ci_shipstate] = shipping_address[:state]
94
+ post[:ci_shipzip] = shipping_address[:zip]
95
+ post[:ci_shipcountry] = shipping_address[:country]
96
+ end
97
+ end
98
+
99
+ def add_invoice(post, money, options)
100
+ post[:amount] = amount(money)
101
+ post[:currencycode] = (options[:currency] || currency(money))
102
+ post[:merchantordernumber] = options[:order_id] if options[:order_id]
103
+ end
104
+
105
+ def add_payment_method(post, payment_method)
106
+ post[:ccname] = payment_method.name
107
+ post[:ccnum] = payment_method.number
108
+ post[:cvv2] = payment_method.verification_value
109
+ post[:expyear] = format(payment_method.year, :four_digits)
110
+ post[:expmon] = format(payment_method.month, :two_digits)
111
+ end
112
+
113
+ def split_authorization(authorization)
114
+ historyid, orderid = authorization.split("|")
115
+ [historyid, orderid]
116
+ end
117
+
118
+ def add_reference(post, authorization)
119
+ historyid, orderid = split_authorization(authorization)
120
+ post[:postonly] = historyid
121
+ post[:historykeyid] = historyid
122
+ post[:orderkeyid] = orderid
123
+ end
124
+
125
+ def parse(xml)
126
+ response = {}
127
+ doc = Nokogiri::XML(xml)
128
+ message = doc.xpath("//plaintext")
129
+ message.text.split(/\r?\n/).each do |line|
130
+ key, value = line.split(%r{=})
131
+ response[key] = value if key
132
+ end
133
+ response
134
+ end
135
+
136
+ ACTIONS = {
137
+ "purchase" => "ns_quicksale_cc",
138
+ "refund" => "ns_credit",
139
+ "authorize" => "ns_quicksale_cc",
140
+ "capture" => "ns_quicksale_cc",
141
+ "void" => "ns_void",
142
+ }
143
+
144
+ def commit(action, post)
145
+ post[:action] = ACTIONS[action] if ACTIONS[action]
146
+ post[:acctid] = @options[:acctid]
147
+ post[:subid] = @options[:subid]
148
+ post[:merchantpin] = @options[:merchantpin]
149
+
150
+ post[:authonly] = '1' if action == 'authorize'
151
+
152
+ raw = parse(ssl_post(live_url, post.to_query))
153
+
154
+ succeeded = success_from(raw['transresult'])
155
+ Response.new(
156
+ succeeded,
157
+ message_from(succeeded, raw),
158
+ raw,
159
+ :authorization => authorization_from(raw),
160
+ :test => test?
161
+ )
162
+ end
163
+
164
+ def success_from(result)
165
+ result == 'APPROVED'
166
+ end
167
+
168
+ def message_from(succeeded, response)
169
+ if succeeded
170
+ "Succeeded"
171
+ else
172
+ (response['transresult'] || response['Reason'] || "Unable to read error message")
173
+ end
174
+ end
175
+
176
+ def authorization_from(response)
177
+ [response['historyid'], response['orderid']].join("|")
178
+ end
179
+ end
180
+ end
181
+ end