fishman-activemerchant 1.18.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 (188) hide show
  1. data/CHANGELOG +733 -0
  2. data/CONTRIBUTORS +257 -0
  3. data/MIT-LICENSE +20 -0
  4. data/gem-public_cert.pem +20 -0
  5. data/lib/active_merchant.rb +47 -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 +260 -0
  11. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  12. data/lib/active_merchant/billing/credit_card_methods.rb +125 -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 +693 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
  19. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  20. data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
  21. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -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 +303 -0
  28. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -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/cyber_source.rb +430 -0
  32. data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
  33. data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
  34. data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
  35. data/lib/active_merchant/billing/gateways/epay.rb +274 -0
  36. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  37. data/lib/active_merchant/billing/gateways/eway_managed.rb +264 -0
  38. data/lib/active_merchant/billing/gateways/exact.rb +222 -0
  39. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  40. data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
  41. data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
  42. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  43. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  44. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  45. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  46. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  47. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  48. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  49. data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
  50. data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
  51. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +156 -0
  52. data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
  53. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  54. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
  55. data/lib/active_merchant/billing/gateways/moneris.rb +209 -0
  56. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  57. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  58. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  59. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  60. data/lib/active_merchant/billing/gateways/ogone.rb +292 -0
  61. data/lib/active_merchant/billing/gateways/optimal_payment.rb +274 -0
  62. data/lib/active_merchant/billing/gateways/orbital.rb +321 -0
  63. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  64. data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
  65. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  66. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  67. data/lib/active_merchant/billing/gateways/payflow.rb +253 -0
  68. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
  69. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  70. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  71. data/lib/active_merchant/billing/gateways/payflow_express.rb +222 -0
  72. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  73. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  74. data/lib/active_merchant/billing/gateways/payment_express.rb +235 -0
  75. data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
  76. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +354 -0
  77. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
  78. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  79. data/lib/active_merchant/billing/gateways/paypal_express.rb +184 -0
  80. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  81. data/lib/active_merchant/billing/gateways/paypal_express_de.rb +14 -0
  82. data/lib/active_merchant/billing/gateways/paystation.rb +201 -0
  83. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  84. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  85. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  86. data/lib/active_merchant/billing/gateways/qbms.rb +297 -0
  87. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  88. data/lib/active_merchant/billing/gateways/quickpay.rb +297 -0
  89. data/lib/active_merchant/billing/gateways/realex.rb +311 -0
  90. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  91. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  92. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  93. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  94. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  95. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  96. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  97. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  98. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
  99. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  100. data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
  101. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  102. data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
  103. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  104. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  105. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  106. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  107. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  108. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  109. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  110. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  111. data/lib/active_merchant/billing/integrations.rb +17 -0
  112. data/lib/active_merchant/billing/integrations/action_view_helper.rb +68 -0
  113. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  114. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  115. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  116. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  117. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  118. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  119. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  120. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  121. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  122. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  123. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  124. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  125. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  126. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  127. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  128. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  129. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  130. data/lib/active_merchant/billing/integrations/dwolla.rb +30 -0
  131. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +28 -0
  132. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +50 -0
  133. data/lib/active_merchant/billing/integrations/dwolla/return.rb +38 -0
  134. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  135. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  136. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  137. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  138. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  139. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  140. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  141. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  142. data/lib/active_merchant/billing/integrations/helper.rb +96 -0
  143. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  144. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  145. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  146. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  147. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  148. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  149. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  150. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  151. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  152. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  153. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  154. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  155. data/lib/active_merchant/billing/integrations/payflow_link.rb +21 -0
  156. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +58 -0
  157. data/lib/active_merchant/billing/integrations/payflow_link/notification.rb +78 -0
  158. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  159. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  160. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  161. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  162. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  163. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  164. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  165. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  166. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  167. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  168. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  169. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  170. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  171. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  172. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  173. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  174. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  175. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  176. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  177. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  178. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  179. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  180. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  181. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  182. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  183. data/lib/active_merchant/billing/response.rb +32 -0
  184. data/lib/active_merchant/version.rb +3 -0
  185. data/lib/activemerchant.rb +1 -0
  186. data/lib/support/gateway_support.rb +58 -0
  187. data/lib/support/outbound_hosts.rb +25 -0
  188. metadata +335 -0
@@ -0,0 +1,274 @@
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] && !addr[:address1].empty?
250
+ xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2] && !addr[:address2].empty?
251
+ xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city] && !addr[:city].empty?
252
+ xml.tag! 'state' , CGI.escape(addr[:state] ) if addr[:state] && !addr[:state].empty?
253
+ xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country] && !addr[:country].empty?
254
+ xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
255
+ xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone] && !addr[:phone].empty?
256
+ #xml.tag! 'email' , ''
257
+ end
258
+ end
259
+
260
+ def card_type(key)
261
+ { 'visa' => 'VI',
262
+ 'master' => 'MC',
263
+ 'american_express'=> 'AM',
264
+ 'discover' => 'DI',
265
+ 'diners_club' => 'DC',
266
+ #'switch' => '',
267
+ 'solo' => 'SO'
268
+ }[key]
269
+ end
270
+
271
+ end
272
+ end
273
+ end
274
+
@@ -0,0 +1,321 @@
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
+ unless options[:ip_authentication] == true
82
+ requires!(options, :login, :password, :merchant_id)
83
+ end
84
+ @options = options
85
+ super
86
+ end
87
+
88
+ # A – Authorization request
89
+ def authorize(money, creditcard, options = {})
90
+ order = build_new_order_xml('A', money, options) do |xml|
91
+ add_creditcard(xml, creditcard, options[:currency])
92
+ add_address(xml, creditcard, options)
93
+ end
94
+ commit(order)
95
+ end
96
+
97
+ # AC – Authorization and Capture
98
+ def purchase(money, creditcard, options = {})
99
+ order = build_new_order_xml('AC', money, options) do |xml|
100
+ add_creditcard(xml, creditcard, options[:currency])
101
+ add_address(xml, creditcard, options)
102
+ end
103
+ commit(order)
104
+ end
105
+
106
+ # MFC - Mark For Capture
107
+ def capture(money, authorization, options = {})
108
+ commit(build_mark_for_capture_xml(money, authorization, options))
109
+ end
110
+
111
+ # R – Refund request
112
+ def refund(money, authorization, options = {})
113
+ order = build_new_order_xml('R', money, options.merge(:authorization => authorization)) do |xml|
114
+ add_refund(xml, options[:currency])
115
+ end
116
+ commit(order)
117
+ end
118
+
119
+ def credit(money, authorization, options= {})
120
+ deprecated CREDIT_DEPRECATION_MESSAGE
121
+ refund(money, authorization, options)
122
+ end
123
+
124
+ # setting money to nil will perform a full void
125
+ def void(money, authorization, options = {})
126
+ order = build_void_request_xml(money, authorization, options)
127
+ commit(order)
128
+ end
129
+
130
+ private
131
+
132
+ def add_customer_data(xml, options)
133
+ if options[:customer_ref_num]
134
+ xml.tag! :CustomerProfileFromOrderInd, 'S'
135
+ xml.tag! :CustomerRefNum, options[:customer_ref_num]
136
+ else
137
+ xml.tag! :CustomerProfileFromOrderInd, 'A'
138
+ end
139
+ end
140
+
141
+ def add_soft_descriptors(xml, soft_desc)
142
+ xml.tag! :SDMerchantName, soft_desc.merchant_name
143
+ xml.tag! :SDProductDescription, soft_desc.product_description
144
+ xml.tag! :SDMerchantCity, soft_desc.merchant_city
145
+ xml.tag! :SDMerchantPhone, soft_desc.merchant_phone
146
+ xml.tag! :SDMerchantURL, soft_desc.merchant_url
147
+ xml.tag! :SDMerchantEmail, soft_desc.merchant_email
148
+ end
149
+
150
+ def add_address(xml, creditcard, options)
151
+ if address = options[:billing_address] || options[:address]
152
+ xml.tag! :AVSzip, address[:zip]
153
+ xml.tag! :AVSaddress1, address[:address1]
154
+ xml.tag! :AVSaddress2, address[:address2]
155
+ xml.tag! :AVScity, address[:city]
156
+ xml.tag! :AVSstate, address[:state]
157
+ xml.tag! :AVSphoneNum, address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil
158
+ xml.tag! :AVSname, creditcard.name
159
+ xml.tag! :AVScountryCode, address[:country]
160
+ end
161
+ end
162
+
163
+ def add_creditcard(xml, creditcard, currency=nil)
164
+ xml.tag! :AccountNum, creditcard.number
165
+ xml.tag! :Exp, expiry_date(creditcard)
166
+
167
+ xml.tag! :CurrencyCode, currency_code(currency)
168
+ xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
169
+
170
+ xml.tag! :CardSecValInd, 1 if creditcard.verification_value? && %w( visa discover ).include?(creditcard.type)
171
+ xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
172
+ end
173
+
174
+ def add_refund(xml, currency=nil)
175
+ xml.tag! :AccountNum, nil
176
+
177
+ xml.tag! :CurrencyCode, currency_code(currency)
178
+ xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
179
+ end
180
+
181
+ def parse(body)
182
+ response = {}
183
+ xml = REXML::Document.new(body)
184
+ root = REXML::XPath.first(xml, "//Response") ||
185
+ REXML::XPath.first(xml, "//ErrorResponse")
186
+ if root
187
+ root.elements.to_a.each do |node|
188
+ recurring_parse_element(response, node)
189
+ end
190
+ end
191
+ response
192
+ end
193
+
194
+ def recurring_parse_element(response, node)
195
+ if node.has_elements?
196
+ node.elements.each{|e| recurring_parse_element(response, e) }
197
+ else
198
+ response[node.name.underscore.to_sym] = node.text
199
+ end
200
+ end
201
+
202
+ def commit(order)
203
+ headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
204
+ request = lambda {return parse(ssl_post(remote_url, order, headers))}
205
+
206
+ # Failover URL will be used in the event of a connection error
207
+ begin response = request.call; rescue ConnectionError; retry end
208
+
209
+ Response.new(success?(response), message_from(response), response,
210
+ {:authorization => "#{response[:tx_ref_num]};#{response[:order_id]}",
211
+ :test => self.test?,
212
+ :avs_result => {:code => response[:avs_resp_code]},
213
+ :cvv_result => response[:cvv2_resp_code]
214
+ }
215
+ )
216
+ end
217
+
218
+ def remote_url
219
+ unless $!.class == ActiveMerchant::ConnectionError
220
+ self.test? ? self.primary_test_url : self.primary_live_url
221
+ else
222
+ self.test? ? self.secondary_test_url : self.secondary_live_url
223
+ end
224
+ end
225
+
226
+ def success?(response)
227
+ if response[:message_type].nil? || response[:message_type] == "R"
228
+ response[:proc_status] == SUCCESS
229
+ else
230
+ response[:proc_status] == SUCCESS &&
231
+ response[:resp_code] == APPROVED
232
+ end
233
+ end
234
+
235
+ def message_from(response)
236
+ success?(response) ? 'APPROVED' : response[:resp_msg] || response[:status_msg]
237
+ end
238
+
239
+ def ip_authentication?
240
+ @options[:ip_authentication] == true
241
+ end
242
+
243
+ def build_new_order_xml(action, money, parameters = {})
244
+ requires!(parameters, :order_id)
245
+ xml = Builder::XmlMarkup.new(:indent => 2)
246
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
247
+ xml.tag! :Request do
248
+ xml.tag! :NewOrder do
249
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
250
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
251
+ xml.tag! :IndustryType, parameters[:industry_type] || "EC"
252
+ xml.tag! :MessageType, action
253
+ xml.tag! :BIN, '000002' # PNS Tampa
254
+ xml.tag! :MerchantID, @options[:merchant_id]
255
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
256
+
257
+ yield xml if block_given?
258
+
259
+ xml.tag! :Comments, parameters[:comments] if parameters[:comments]
260
+ xml.tag! :OrderID, parameters[:order_id].to_s[0...22]
261
+ xml.tag! :Amount, amount(money)
262
+
263
+ # Append Transaction Reference Number at the end for Refund transactions
264
+ if action == "R"
265
+ tx_ref_num, _ = parameters[:authorization].split(';')
266
+ xml.tag! :TxRefNum, tx_ref_num
267
+ end
268
+ end
269
+ end
270
+ xml.target!
271
+ end
272
+
273
+ def build_mark_for_capture_xml(money, authorization, parameters = {})
274
+ tx_ref_num, order_id = authorization.split(';')
275
+ xml = Builder::XmlMarkup.new(:indent => 2)
276
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
277
+ xml.tag! :Request do
278
+ xml.tag! :MarkForCapture do
279
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
280
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
281
+ xml.tag! :OrderID, order_id
282
+ xml.tag! :Amount, amount(money)
283
+ xml.tag! :BIN, '000002' # PNS Tampa
284
+ xml.tag! :MerchantID, @options[:merchant_id]
285
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
286
+ xml.tag! :TxRefNum, tx_ref_num
287
+ end
288
+ end
289
+ xml.target!
290
+ end
291
+
292
+ def build_void_request_xml(money, authorization, parameters = {})
293
+ tx_ref_num, order_id = authorization.split(';')
294
+ xml = Builder::XmlMarkup.new(:indent => 2)
295
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
296
+ xml.tag! :Request do
297
+ xml.tag! :Reversal do
298
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
299
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
300
+ xml.tag! :TxRefNum, tx_ref_num
301
+ xml.tag! :TxRefIdx, parameters[:transaction_index]
302
+ xml.tag! :AdjustedAmt, amount(money)
303
+ xml.tag! :OrderID, order_id
304
+ xml.tag! :BIN, '000002' # PNS Tampa
305
+ xml.tag! :MerchantID, @options[:merchant_id]
306
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
307
+ end
308
+ end
309
+ xml.target!
310
+ end
311
+
312
+ def currency_code(currency)
313
+ CURRENCY_CODES[(currency || self.default_currency)].to_s
314
+ end
315
+
316
+ def expiry_date(credit_card)
317
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
318
+ end
319
+ end
320
+ end
321
+ end