tlconnor-activemerchant 1.20.4

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 (195) hide show
  1. data/CHANGELOG +805 -0
  2. data/CONTRIBUTORS +274 -0
  3. data/MIT-LICENSE +20 -0
  4. data/gem-public_cert.pem +20 -0
  5. data/lib/active_merchant.rb +63 -0
  6. data/lib/active_merchant/billing.rb +9 -0
  7. data/lib/active_merchant/billing/avs_result.rb +98 -0
  8. data/lib/active_merchant/billing/base.rb +57 -0
  9. data/lib/active_merchant/billing/check.rb +68 -0
  10. data/lib/active_merchant/billing/credit_card.rb +264 -0
  11. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  12. data/lib/active_merchant/billing/credit_card_methods.rb +129 -0
  13. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  14. data/lib/active_merchant/billing/expiry_date.rb +34 -0
  15. data/lib/active_merchant/billing/gateway.rb +170 -0
  16. data/lib/active_merchant/billing/gateways.rb +18 -0
  17. data/lib/active_merchant/billing/gateways/authorize_net.rb +694 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +944 -0
  19. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  20. data/lib/active_merchant/billing/gateways/beanstream.rb +167 -0
  21. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +388 -0
  22. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  23. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  24. data/lib/active_merchant/billing/gateways/bogus.rb +142 -0
  25. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  26. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  27. data/lib/active_merchant/billing/gateways/braintree_blue.rb +308 -0
  28. data/lib/active_merchant/billing/gateways/braintree_orange.rb +21 -0
  29. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  30. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
  31. data/lib/active_merchant/billing/gateways/certo_direct.rb +279 -0
  32. data/lib/active_merchant/billing/gateways/cyber_source.rb +430 -0
  33. data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
  34. data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
  35. data/lib/active_merchant/billing/gateways/elavon.rb +135 -0
  36. data/lib/active_merchant/billing/gateways/epay.rb +274 -0
  37. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/eway_managed.rb +265 -0
  39. data/lib/active_merchant/billing/gateways/exact.rb +227 -0
  40. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  41. data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
  42. data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
  43. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  44. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  45. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  46. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  47. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  48. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  49. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  50. data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
  51. data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
  52. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +157 -0
  53. data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
  54. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  55. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
  56. data/lib/active_merchant/billing/gateways/moneris.rb +239 -0
  57. data/lib/active_merchant/billing/gateways/nab_transact.rb +244 -0
  58. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  59. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  60. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  61. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  62. data/lib/active_merchant/billing/gateways/ogone.rb +330 -0
  63. data/lib/active_merchant/billing/gateways/optimal_payment.rb +277 -0
  64. data/lib/active_merchant/billing/gateways/orbital.rb +344 -0
  65. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  66. data/lib/active_merchant/billing/gateways/pay_junction.rb +397 -0
  67. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  68. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  69. data/lib/active_merchant/billing/gateways/payflow.rb +261 -0
  70. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +208 -0
  71. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  72. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  73. data/lib/active_merchant/billing/gateways/payflow_express.rb +222 -0
  74. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  75. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  76. data/lib/active_merchant/billing/gateways/payment_express.rb +235 -0
  77. data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
  78. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +354 -0
  79. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
  80. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  81. data/lib/active_merchant/billing/gateways/paypal_express.rb +229 -0
  82. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  83. data/lib/active_merchant/billing/gateways/paystation.rb +201 -0
  84. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  85. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  86. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  87. data/lib/active_merchant/billing/gateways/qbms.rb +297 -0
  88. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  89. data/lib/active_merchant/billing/gateways/quickpay.rb +298 -0
  90. data/lib/active_merchant/billing/gateways/realex.rb +315 -0
  91. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  92. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  93. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  94. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  95. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  96. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  97. data/lib/active_merchant/billing/gateways/samurai.rb +121 -0
  98. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  99. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  100. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +280 -0
  101. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  102. data/lib/active_merchant/billing/gateways/skip_jack.rb +458 -0
  103. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  104. data/lib/active_merchant/billing/gateways/stripe.rb +244 -0
  105. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  106. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  107. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  108. data/lib/active_merchant/billing/gateways/usa_epay.rb +23 -0
  109. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1496 -0
  110. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +206 -0
  111. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  112. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  113. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  114. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  115. data/lib/active_merchant/billing/integrations.rb +17 -0
  116. data/lib/active_merchant/billing/integrations/action_view_helper.rb +72 -0
  117. data/lib/active_merchant/billing/integrations/authorize_net_sim.rb +38 -0
  118. data/lib/active_merchant/billing/integrations/authorize_net_sim/helper.rb +228 -0
  119. data/lib/active_merchant/billing/integrations/authorize_net_sim/notification.rb +340 -0
  120. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  121. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  122. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  123. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  124. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  125. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  126. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  127. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  128. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  129. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  130. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  131. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  132. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  133. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  134. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  135. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  136. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  137. data/lib/active_merchant/billing/integrations/dwolla.rb +30 -0
  138. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +31 -0
  139. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +55 -0
  140. data/lib/active_merchant/billing/integrations/dwolla/return.rb +38 -0
  141. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  142. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  143. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  144. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  145. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  146. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  147. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  148. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  149. data/lib/active_merchant/billing/integrations/helper.rb +113 -0
  150. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  151. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  152. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  153. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  154. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  155. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  156. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  157. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  158. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  159. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  160. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  161. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  162. data/lib/active_merchant/billing/integrations/payflow_link.rb +21 -0
  163. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +100 -0
  164. data/lib/active_merchant/billing/integrations/payflow_link/notification.rb +78 -0
  165. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  166. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  167. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  168. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  169. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  170. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  171. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  172. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  173. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  174. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  175. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +127 -0
  176. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  177. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  178. data/lib/active_merchant/billing/integrations/two_checkout.rb +22 -0
  179. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  180. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  181. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  182. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  183. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  184. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  185. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  186. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  187. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  188. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  189. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  190. data/lib/active_merchant/billing/response.rb +32 -0
  191. data/lib/active_merchant/version.rb +3 -0
  192. data/lib/activemerchant.rb +1 -0
  193. data/lib/support/gateway_support.rb +58 -0
  194. data/lib/support/outbound_hosts.rb +25 -0
  195. metadata +411 -0
@@ -0,0 +1,277 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class OptimalPaymentGateway < Gateway
4
+ TEST_URL = 'https://webservices.test.optimalpayments.com/creditcardWS/CreditCardServlet/v1'
5
+ LIVE_URL = 'https://webservices.optimalpayments.com/creditcardWS/CreditCardServlet/v1'
6
+
7
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
8
+ self.supported_countries = ['CA', 'US', 'GB']
9
+
10
+ # The card types supported by the payment gateway
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :solo] # :switch?
12
+
13
+ # The homepage URL of the gateway
14
+ self.homepage_url = 'http://www.optimalpayments.com/'
15
+
16
+ # The name of the gateway
17
+ self.display_name = 'Optimal Payments'
18
+
19
+ def initialize(options = {})
20
+ #requires!(options, :login, :password)
21
+ @options = options
22
+ super
23
+ end
24
+
25
+ def authorize(money, card_or_auth, options = {})
26
+ parse_card_or_auth(card_or_auth, options)
27
+ commit("cc#{@stored_data}Authorize", money, options)
28
+ end
29
+ alias stored_authorize authorize # back-compat
30
+
31
+ def purchase(money, card_or_auth, options = {})
32
+ parse_card_or_auth(card_or_auth, options)
33
+ commit("cc#{@stored_data}Purchase", money, options)
34
+ end
35
+ alias stored_purchase purchase # back-compat
36
+
37
+ def refund(money, authorization, options = {})
38
+ options[:confirmationNumber] = authorization
39
+ commit('ccCredit', money, options)
40
+ end
41
+
42
+ def void(authorization, options = {})
43
+ options[:confirmationNumber] = authorization
44
+ commit('ccAuthorizeReversal', nil, options)
45
+ end
46
+
47
+ def capture(money, authorization, options = {})
48
+ options[:confirmationNumber] = authorization
49
+ commit('ccSettlement', money, options)
50
+ end
51
+
52
+ def test?
53
+ super || @options[:test]
54
+ end
55
+
56
+ private
57
+
58
+ def parse_card_or_auth(card_or_auth, options)
59
+ if card_or_auth.respond_to?(:number)
60
+ @credit_card = card_or_auth
61
+ @stored_data = ""
62
+ else
63
+ options[:confirmationNumber] = card_or_auth
64
+ @stored_data = "StoredData"
65
+ end
66
+ end
67
+
68
+ def parse(body)
69
+ REXML::Document.new(body || '')
70
+ end
71
+
72
+ def commit(action, money, post)
73
+ post[:order_id] ||= 'order_id'
74
+
75
+ xml = case action
76
+ when 'ccAuthorize', 'ccPurchase', 'ccVerification'
77
+ cc_auth_request(money, post)
78
+ when 'ccCredit', 'ccSettlement'
79
+ cc_post_auth_request(money, post)
80
+ when 'ccStoredDataAuthorize', 'ccStoredDataPurchase'
81
+ cc_stored_data_request(money, post)
82
+ when 'ccAuthorizeReversal'
83
+ cc_auth_reversal_request(post)
84
+ #when 'ccCancelSettle', 'ccCancelCredit', 'ccCancelPayment'
85
+ # cc_cancel_request(money, post)
86
+ #when 'ccPayment'
87
+ # cc_payment_request(money, post)
88
+ #when 'ccAuthenticate'
89
+ # cc_authenticate_request(money, post)
90
+ else
91
+ raise 'Unknown Action'
92
+ end
93
+ txnRequest = URI.encode(xml)
94
+ response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, "txnMode=#{action}&txnRequest=#{txnRequest}"))
95
+
96
+ Response.new(successful?(response), message_from(response), hash_from_xml(response),
97
+ :test => test?,
98
+ :authorization => authorization_from(response)
99
+ )
100
+ end
101
+
102
+ def successful?(response)
103
+ REXML::XPath.first(response, '//decision').text == 'ACCEPTED' rescue false
104
+ end
105
+
106
+ def message_from(response)
107
+ REXML::XPath.each(response, '//detail') do |detail|
108
+ if detail.is_a?(REXML::Element) && detail.elements['tag'].text == 'InternalResponseDescription'
109
+ return detail.elements['value'].text
110
+ end
111
+ end
112
+ nil
113
+ end
114
+
115
+ def authorization_from(response)
116
+ REXML::XPath.first(response, '//confirmationNumber').text rescue nil
117
+ end
118
+
119
+ def hash_from_xml(response)
120
+ hsh = {}
121
+ %w(confirmationNumber authCode
122
+ decision code description
123
+ actionCode avsResponse cvdResponse
124
+ txnTime duplicateFound
125
+ ).each do |tag|
126
+ node = REXML::XPath.first(response, "//#{tag}")
127
+ hsh[tag] = node.text if node
128
+ end
129
+ REXML::XPath.each(response, '//detail') do |detail|
130
+ next unless detail.is_a?(REXML::Element)
131
+ tag = detail.elements['tag'].text
132
+ value = detail.elements['value'].text
133
+ hsh[tag] = value
134
+ end
135
+ hsh
136
+ end
137
+
138
+ def xml_document(root_tag)
139
+ xml = Builder::XmlMarkup.new :indent => 2
140
+ xml.tag!(root_tag, schema) do
141
+ yield xml
142
+ end
143
+ xml.target!
144
+ end
145
+
146
+ def cc_auth_request(money, opts)
147
+ xml_document('ccAuthRequestV1') do |xml|
148
+ build_merchant_account(xml, @options)
149
+ xml.merchantRefNum opts[:order_id]
150
+ xml.amount(money/100.0)
151
+ build_card(xml, opts)
152
+ build_billing_details(xml, opts)
153
+ end
154
+ end
155
+
156
+ def cc_auth_reversal_request(opts)
157
+ xml_document('ccAuthReversalRequestV1') do |xml|
158
+ build_merchant_account(xml, @options)
159
+ xml.confirmationNumber opts[:confirmationNumber]
160
+ xml.merchantRefNum opts[:order_id]
161
+ end
162
+ end
163
+
164
+ def cc_post_auth_request(money, opts)
165
+ xml_document('ccPostAuthRequestV1') do |xml|
166
+ build_merchant_account(xml, @options)
167
+ xml.confirmationNumber opts[:confirmationNumber]
168
+ xml.merchantRefNum opts[:order_id]
169
+ xml.amount(money/100.0)
170
+ end
171
+ end
172
+
173
+ def cc_stored_data_request(money, opts)
174
+ xml_document('ccStoredDataRequestV1') do |xml|
175
+ build_merchant_account(xml, @options)
176
+ xml.merchantRefNum opts[:order_id]
177
+ xml.confirmationNumber opts[:confirmationNumber]
178
+ xml.amount(money/100.0)
179
+ end
180
+ end
181
+
182
+ # untested
183
+ #
184
+ # def cc_cancel_request(opts)
185
+ # xml_document('ccCancelRequestV1') do |xml|
186
+ # build_merchant_account(xml, @options)
187
+ # xml.confirmationNumber opts[:confirmationNumber]
188
+ # end
189
+ # end
190
+ #
191
+ # def cc_payment_request(money, opts)
192
+ # xml_document('ccPaymentRequestV1') do |xml|
193
+ # build_merchant_account(xml, @options)
194
+ # xml.merchantRefNum opts[:order_id]
195
+ # xml.amount(money/100.0)
196
+ # build_card(xml, opts)
197
+ # build_billing_details(xml, opts)
198
+ # end
199
+ # end
200
+ #
201
+ # def cc_authenticate_request(opts)
202
+ # xml_document('ccAuthenticateRequestV1') do |xml|
203
+ # build_merchant_account(xml, @options)
204
+ # xml.confirmationNumber opts[:confirmationNumber]
205
+ # xml.paymentResponse 'myPaymentResponse'
206
+ # end
207
+ # end
208
+
209
+ def schema
210
+ { 'xmlns' => 'http://www.optimalpayments.com/creditcard/xmlschema/v1',
211
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
212
+ 'xsi:schemaLocation' => 'http://www.optimalpayments.com/creditcard/xmlschema/v1'
213
+ }
214
+ end
215
+
216
+ def build_merchant_account(xml, opts)
217
+ xml.tag! 'merchantAccount' do
218
+ xml.tag! 'accountNum' , opts[:account]
219
+ xml.tag! 'storeID' , opts[:login]
220
+ xml.tag! 'storePwd' , opts[:password]
221
+ end
222
+ end
223
+
224
+ def build_card(xml, opts)
225
+ xml.tag! 'card' do
226
+ xml.tag! 'cardNum' , @credit_card.number
227
+ xml.tag! 'cardExpiry' do
228
+ xml.tag! 'month' , @credit_card.month
229
+ xml.tag! 'year' , @credit_card.year
230
+ end
231
+ if type = card_type(@credit_card.type)
232
+ xml.tag! 'cardType' , type
233
+ end
234
+ if @credit_card.verification_value
235
+ xml.tag! 'cvdIndicator' , '1' # Value Provided
236
+ xml.tag! 'cvd' , @credit_card.verification_value
237
+ end
238
+ end
239
+ end
240
+
241
+ def build_billing_details(xml, opts)
242
+ xml.tag! 'billingDetails' do
243
+ addr = opts[:billing_address]
244
+ xml.tag! 'cardPayMethod', 'WEB'
245
+ if addr[:name]
246
+ xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
247
+ xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
248
+ end
249
+ xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1].present?
250
+ xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2].present?
251
+ xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city].present?
252
+ if addr[:state].present?
253
+ state_tag = %w(US CA).include?(addr[:country]) ? 'state' : 'region'
254
+ xml.tag! state_tag, CGI.escape(addr[:state])
255
+ end
256
+ xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
257
+ xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
258
+ xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
259
+ #xml.tag! 'email' , ''
260
+ end
261
+ end
262
+
263
+ def card_type(key)
264
+ { 'visa' => 'VI',
265
+ 'master' => 'MC',
266
+ 'american_express'=> 'AM',
267
+ 'discover' => 'DI',
268
+ 'diners_club' => 'DC',
269
+ #'switch' => '',
270
+ 'solo' => 'SO'
271
+ }[key]
272
+ end
273
+
274
+ end
275
+ end
276
+ end
277
+
@@ -0,0 +1,344 @@
1
+ require File.dirname(__FILE__) + '/orbital/orbital_soft_descriptors.rb'
2
+ require "rexml/document"
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ # For more information on Orbital, visit the {integration center}[http://download.chasepaymentech.com]
7
+ #
8
+ # ==== Authentication Options
9
+ #
10
+ # The Orbital Gateway supports two methods of authenticating incoming requests:
11
+ # Source IP authentication and Connection Username/Password authentication
12
+ #
13
+ # In addition, these IP addresses/Connection Usernames must be affiliated with the Merchant IDs
14
+ # for which the client should be submitting transactions.
15
+ #
16
+ # This does allow Third Party Hosting service organizations presenting on behalf of other
17
+ # merchants to submit transactions. However, each time a new customer is added, the
18
+ # merchant or Third-Party hosting organization needs to ensure that the new Merchant IDs
19
+ # or Chain IDs are affiliated with the hosting companies IPs or Connection Usernames.
20
+ #
21
+ # If the merchant expects to have more than one merchant account with the Orbital
22
+ # Gateway, it should have its IP addresses/Connection Usernames affiliated at the Chain
23
+ # level hierarchy within the Orbital Gateway. Each time a new merchant ID is added, as
24
+ # long as it is placed within the same Chain, it will simply work. Otherwise, the additional
25
+ # MIDs will need to be affiliated with the merchant IPs or Connection Usernames respectively.
26
+ # For example, we generally affiliate all Salem accounts [BIN 000001] with
27
+ # their Company Number [formerly called MA #] number so all MIDs or Divisions under that
28
+ # Company will automatically be affiliated.
29
+
30
+ class OrbitalGateway < Gateway
31
+ API_VERSION = "4.6"
32
+
33
+ POST_HEADERS = {
34
+ "MIME-Version" => "1.0",
35
+ "Content-Type" => "Application/PTI46",
36
+ "Content-transfer-encoding" => "text",
37
+ "Request-number" => '1',
38
+ "Document-type" => "Request",
39
+ "Interface-Version" => "Ruby|ActiveMerchant|Proprietary Gateway"
40
+ }
41
+
42
+ SUCCESS, APPROVED = '0', '00'
43
+
44
+ class_attribute :primary_test_url, :secondary_test_url, :primary_live_url, :secondary_live_url
45
+
46
+ self.primary_test_url = "https://orbitalvar1.paymentech.net/authorize"
47
+ self.secondary_test_url = "https://orbitalvar2.paymentech.net/authorize"
48
+
49
+ self.primary_live_url = "https://orbital1.paymentech.net/authorize"
50
+ self.secondary_live_url = "https://orbital2.paymentech.net/authorize"
51
+
52
+ self.supported_countries = ["US", "CA"]
53
+ self.default_currency = "CAD"
54
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
55
+
56
+ self.display_name = 'Orbital Paymentech'
57
+ self.homepage_url = 'http://chasepaymentech.com/'
58
+
59
+ self.money_format = :cents
60
+
61
+ CURRENCY_CODES = {
62
+ "AUD" => '036',
63
+ "CAD" => '124',
64
+ "CZK" => '203',
65
+ "DKK" => '208',
66
+ "HKD" => '344',
67
+ "ICK" => '352',
68
+ "JPY" => '392',
69
+ "MXN" => '484',
70
+ "NZD" => '554',
71
+ "NOK" => '578',
72
+ "SGD" => '702',
73
+ "SEK" => '752',
74
+ "CHF" => '756',
75
+ "GBP" => '826',
76
+ "USD" => '840',
77
+ "EUR" => '978'
78
+ }
79
+
80
+ def initialize(options = {})
81
+ requires!(options, :merchant_id)
82
+ requires!(options, :login, :password) unless options[:ip_authentication]
83
+ @options = options
84
+ super
85
+ end
86
+
87
+ # A – Authorization request
88
+ def authorize(money, creditcard, options = {})
89
+ order = build_new_order_xml('A', money, options) do |xml|
90
+ add_creditcard(xml, creditcard, options[:currency])
91
+ add_address(xml, creditcard, options)
92
+ end
93
+ commit(order)
94
+ end
95
+
96
+ # AC – Authorization and Capture
97
+ def purchase(money, creditcard, options = {})
98
+ order = build_new_order_xml('AC', money, options) do |xml|
99
+ add_creditcard(xml, creditcard, options[:currency])
100
+ add_address(xml, creditcard, options)
101
+ end
102
+ commit(order)
103
+ end
104
+
105
+ # MFC - Mark For Capture
106
+ def capture(money, authorization, options = {})
107
+ commit(build_mark_for_capture_xml(money, authorization, options))
108
+ end
109
+
110
+ # R – Refund request
111
+ def refund(money, authorization, options = {})
112
+ order = build_new_order_xml('R', money, options.merge(:authorization => authorization)) do |xml|
113
+ add_refund(xml, options[:currency])
114
+ end
115
+ commit(order)
116
+ end
117
+
118
+ def credit(money, authorization, options= {})
119
+ deprecated CREDIT_DEPRECATION_MESSAGE
120
+ refund(money, authorization, options)
121
+ end
122
+
123
+ # setting money to nil will perform a full void
124
+ def void(authorization, options = {})
125
+ order = build_void_request_xml(authorization, options)
126
+ commit(order)
127
+ end
128
+
129
+ private
130
+
131
+ def add_customer_data(xml, options)
132
+ if options[:customer_ref_num]
133
+ xml.tag! :CustomerProfileFromOrderInd, 'S'
134
+ xml.tag! :CustomerRefNum, options[:customer_ref_num]
135
+ else
136
+ xml.tag! :CustomerProfileFromOrderInd, 'A'
137
+ end
138
+ end
139
+
140
+ def add_soft_descriptors(xml, soft_desc)
141
+ xml.tag! :SDMerchantName, soft_desc.merchant_name
142
+ xml.tag! :SDProductDescription, soft_desc.product_description
143
+ xml.tag! :SDMerchantCity, soft_desc.merchant_city
144
+ xml.tag! :SDMerchantPhone, soft_desc.merchant_phone
145
+ xml.tag! :SDMerchantURL, soft_desc.merchant_url
146
+ xml.tag! :SDMerchantEmail, soft_desc.merchant_email
147
+ end
148
+
149
+ def add_address(xml, creditcard, options)
150
+ if address = options[:billing_address] || options[:address]
151
+ xml.tag! :AVSzip, address[:zip]
152
+ xml.tag! :AVSaddress1, address[:address1]
153
+ xml.tag! :AVSaddress2, address[:address2]
154
+ xml.tag! :AVScity, address[:city]
155
+ xml.tag! :AVSstate, address[:state]
156
+ xml.tag! :AVSphoneNum, address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil
157
+ xml.tag! :AVSname, creditcard.name
158
+ xml.tag! :AVScountryCode, address[:country]
159
+ end
160
+ end
161
+
162
+ def add_creditcard(xml, creditcard, currency=nil)
163
+ xml.tag! :AccountNum, creditcard.number
164
+ xml.tag! :Exp, expiry_date(creditcard)
165
+
166
+ xml.tag! :CurrencyCode, currency_code(currency)
167
+ xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
168
+
169
+ xml.tag! :CardSecValInd, 1 if creditcard.verification_value? && %w( visa discover ).include?(creditcard.brand)
170
+ xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
171
+ end
172
+
173
+ def add_refund(xml, currency=nil)
174
+ xml.tag! :AccountNum, nil
175
+
176
+ xml.tag! :CurrencyCode, currency_code(currency)
177
+ xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
178
+ end
179
+
180
+ def parse(body)
181
+ response = {}
182
+ xml = REXML::Document.new(body)
183
+ root = REXML::XPath.first(xml, "//Response") ||
184
+ REXML::XPath.first(xml, "//ErrorResponse")
185
+ if root
186
+ root.elements.to_a.each do |node|
187
+ recurring_parse_element(response, node)
188
+ end
189
+ end
190
+ response
191
+ end
192
+
193
+ def recurring_parse_element(response, node)
194
+ if node.has_elements?
195
+ node.elements.each{|e| recurring_parse_element(response, e) }
196
+ else
197
+ response[node.name.underscore.to_sym] = node.text
198
+ end
199
+ end
200
+
201
+ def commit(order)
202
+ headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
203
+ request = lambda {return parse(ssl_post(remote_url, order, headers))}
204
+
205
+ # Failover URL will be used in the event of a connection error
206
+ begin response = request.call; rescue ConnectionError; retry end
207
+
208
+ Response.new(success?(response), message_from(response), response,
209
+ {:authorization => "#{response[:tx_ref_num]};#{response[:order_id]}",
210
+ :test => self.test?,
211
+ :avs_result => {:code => response[:avs_resp_code]},
212
+ :cvv_result => response[:cvv2_resp_code]
213
+ }
214
+ )
215
+ end
216
+
217
+ def remote_url
218
+ unless $!.class == ActiveMerchant::ConnectionError
219
+ self.test? ? self.primary_test_url : self.primary_live_url
220
+ else
221
+ self.test? ? self.secondary_test_url : self.secondary_live_url
222
+ end
223
+ end
224
+
225
+ def success?(response)
226
+ if response[:message_type].nil? || response[:message_type] == "R"
227
+ response[:proc_status] == SUCCESS
228
+ else
229
+ response[:proc_status] == SUCCESS &&
230
+ response[:resp_code] == APPROVED
231
+ end
232
+ end
233
+
234
+ def message_from(response)
235
+ success?(response) ? 'APPROVED' : response[:resp_msg] || response[:status_msg]
236
+ end
237
+
238
+ def ip_authentication?
239
+ @options[:ip_authentication] == true
240
+ end
241
+
242
+ def build_new_order_xml(action, money, parameters = {})
243
+ requires!(parameters, :order_id)
244
+ xml = xml_envelope
245
+ xml.tag! :Request do
246
+ xml.tag! :NewOrder do
247
+ add_xml_credentials(xml)
248
+ xml.tag! :IndustryType, parameters[:industry_type] || "EC"
249
+ xml.tag! :MessageType, action
250
+ add_bin_merchant_and_terminal(xml, parameters)
251
+
252
+ yield xml if block_given?
253
+
254
+ xml.tag! :Comments, parameters[:comments] if parameters[:comments]
255
+ xml.tag! :OrderID, format_order_id(parameters[:order_id])
256
+ xml.tag! :Amount, amount(money)
257
+
258
+ # Append Transaction Reference Number at the end for Refund transactions
259
+ if action == "R"
260
+ tx_ref_num, _ = parameters[:authorization].split(';')
261
+ xml.tag! :TxRefNum, tx_ref_num
262
+ end
263
+ end
264
+ end
265
+ xml.target!
266
+ end
267
+
268
+ def build_mark_for_capture_xml(money, authorization, parameters = {})
269
+ tx_ref_num, order_id = authorization.split(';')
270
+ xml = xml_envelope
271
+ xml.tag! :Request do
272
+ xml.tag! :MarkForCapture do
273
+ add_xml_credentials(xml)
274
+ xml.tag! :OrderID, order_id
275
+ xml.tag! :Amount, amount(money)
276
+ add_bin_merchant_and_terminal(xml, parameters)
277
+ xml.tag! :TxRefNum, tx_ref_num
278
+ end
279
+ end
280
+ xml.target!
281
+ end
282
+
283
+ def build_void_request_xml(authorization, parameters = {})
284
+ tx_ref_num, order_id = authorization.split(';')
285
+ xml = xml_envelope
286
+ xml.tag! :Request do
287
+ xml.tag! :Reversal do
288
+ add_xml_credentials(xml)
289
+ xml.tag! :TxRefNum, tx_ref_num
290
+ xml.tag! :TxRefIdx, parameters[:transaction_index]
291
+ xml.tag! :OrderID, order_id
292
+ add_bin_merchant_and_terminal(xml, parameters)
293
+ end
294
+ end
295
+ xml.target!
296
+ end
297
+
298
+ def currency_code(currency)
299
+ CURRENCY_CODES[(currency || self.default_currency)].to_s
300
+ end
301
+
302
+ def expiry_date(credit_card)
303
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
304
+ end
305
+
306
+ def bin
307
+ @options[:bin] || (salem_mid? ? '000001' : '000002')
308
+ end
309
+
310
+ def xml_envelope
311
+ xml = Builder::XmlMarkup.new(:indent => 2)
312
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
313
+ xml
314
+ end
315
+
316
+ def add_xml_credentials(xml)
317
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
318
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
319
+ end
320
+
321
+ def add_bin_merchant_and_terminal(xml, parameters)
322
+ xml.tag! :BIN, bin
323
+ xml.tag! :MerchantID, @options[:merchant_id]
324
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
325
+ end
326
+
327
+ def salem_mid?
328
+ @options[:merchant_id].length == 6
329
+ end
330
+
331
+ # The valid characters include:
332
+ #
333
+ # 1. all letters and digits
334
+ # 2. - , $ @ & and a space character, though the space character cannot be the leading character
335
+ # 3. PINless Debit transactions can only use uppercase and lowercase alpha (A-Z, a-z) and numeric (0-9)
336
+ def format_order_id(order_id)
337
+ illegal_characters = /[^,$@\- \w]/
338
+ order_id = order_id.to_s.gsub(/\./, '-')
339
+ order_id.gsub!(illegal_characters, '')
340
+ order_id[0...22]
341
+ end
342
+ end
343
+ end
344
+ end