gonow-activemerchant 1.15.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 (189) hide show
  1. data/CHANGELOG +690 -0
  2. data/CONTRIBUTORS +237 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +165 -0
  5. data/gem-public_cert.pem +20 -0
  6. data/lib/active_merchant.rb +47 -0
  7. data/lib/active_merchant/billing.rb +9 -0
  8. data/lib/active_merchant/billing/avs_result.rb +98 -0
  9. data/lib/active_merchant/billing/base.rb +57 -0
  10. data/lib/active_merchant/billing/check.rb +68 -0
  11. data/lib/active_merchant/billing/credit_card.rb +178 -0
  12. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  13. data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
  14. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  15. data/lib/active_merchant/billing/expiry_date.rb +34 -0
  16. data/lib/active_merchant/billing/gateway.rb +170 -0
  17. data/lib/active_merchant/billing/gateways.rb +18 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net.rb +664 -0
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
  20. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  21. data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
  22. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -0
  23. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  24. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  25. data/lib/active_merchant/billing/gateways/bogus.rb +132 -0
  26. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  27. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  28. data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
  29. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
  30. data/lib/active_merchant/billing/gateways/braspag.rb +188 -0
  31. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -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 +134 -0
  36. data/lib/active_merchant/billing/gateways/epay.rb +268 -0
  37. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  39. data/lib/active_merchant/billing/gateways/exact.rb +222 -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 +156 -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 +209 -0
  57. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  58. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  59. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  60. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  61. data/lib/active_merchant/billing/gateways/ogone.rb +292 -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 +351 -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 +177 -0
  80. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  81. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  82. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  83. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  84. data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
  85. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  86. data/lib/active_merchant/billing/gateways/quickpay.rb +218 -0
  87. data/lib/active_merchant/billing/gateways/realex.rb +311 -0
  88. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  89. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  90. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  91. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  92. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  93. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  94. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  95. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  96. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
  97. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  98. data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
  99. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  100. data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
  101. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  102. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  103. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  104. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  105. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  106. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  107. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  108. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  109. data/lib/active_merchant/billing/integrations.rb +17 -0
  110. data/lib/active_merchant/billing/integrations/action_view_helper.rb +68 -0
  111. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  112. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  113. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  114. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  115. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  116. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  117. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  118. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  119. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  120. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  121. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  122. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  123. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  124. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  125. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  126. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  127. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  128. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  129. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  130. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  131. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  132. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  133. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  134. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  135. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  136. data/lib/active_merchant/billing/integrations/helper.rb +96 -0
  137. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  138. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  139. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  140. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  141. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  142. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  143. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  144. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  145. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  146. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  147. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  148. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  149. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  150. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  151. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  152. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  153. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  154. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  155. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  156. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  157. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  158. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  159. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  160. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  161. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  162. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  163. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  164. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  165. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  166. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  167. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  168. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  169. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  170. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  171. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  172. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  173. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  174. data/lib/active_merchant/billing/response.rb +32 -0
  175. data/lib/active_merchant/common.rb +14 -0
  176. data/lib/active_merchant/common/connection.rb +177 -0
  177. data/lib/active_merchant/common/country.rb +328 -0
  178. data/lib/active_merchant/common/error.rb +26 -0
  179. data/lib/active_merchant/common/post_data.rb +24 -0
  180. data/lib/active_merchant/common/posts_data.rb +63 -0
  181. data/lib/active_merchant/common/requires_parameters.rb +16 -0
  182. data/lib/active_merchant/common/utils.rb +22 -0
  183. data/lib/active_merchant/common/validateable.rb +81 -0
  184. data/lib/active_merchant/version.rb +3 -0
  185. data/lib/activemerchant.rb +1 -0
  186. data/lib/certs/cacert.pem +7815 -0
  187. data/lib/support/gateway_support.rb +58 -0
  188. data/lib/support/outbound_hosts.rb +25 -0
  189. metadata +276 -0
@@ -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
+ @options = options
84
+ end
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/).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! :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] == "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 = Builder::XmlMarkup.new(:indent => 2)
245
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
246
+ xml.tag! :Request do
247
+ xml.tag! :NewOrder do
248
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
249
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
250
+ xml.tag! :IndustryType, "EC" # E-Commerce transaction
251
+ xml.tag! :MessageType, action
252
+ xml.tag! :BIN, '000002' # PNS Tampa
253
+ xml.tag! :MerchantID, @options[:merchant_id]
254
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
255
+
256
+ yield xml if block_given?
257
+
258
+ xml.tag! :Comments, parameters[:comments] if parameters[:comments]
259
+ xml.tag! :OrderID, parameters[:order_id].to_s[0...22]
260
+ xml.tag! :Amount, amount(money)
261
+
262
+ # Append Transaction Reference Number at the end for Refund transactions
263
+ if action == "R"
264
+ tx_ref_num, _ = parameters[:authorization].split(';')
265
+ xml.tag! :TxRefNum, tx_ref_num
266
+ end
267
+ end
268
+ end
269
+ xml.target!
270
+ end
271
+
272
+ def build_mark_for_capture_xml(money, authorization, parameters = {})
273
+ tx_ref_num, order_id = authorization.split(';')
274
+ xml = Builder::XmlMarkup.new(:indent => 2)
275
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
276
+ xml.tag! :Request do
277
+ xml.tag! :MarkForCapture do
278
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
279
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
280
+ xml.tag! :OrderID, order_id
281
+ xml.tag! :Amount, amount(money)
282
+ xml.tag! :BIN, '000002' # PNS Tampa
283
+ xml.tag! :MerchantID, @options[:merchant_id]
284
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
285
+ xml.tag! :TxRefNum, tx_ref_num
286
+ end
287
+ end
288
+ xml.target!
289
+ end
290
+
291
+ def build_void_request_xml(money, authorization, parameters = {})
292
+ requires!(parameters, :transaction_index)
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
@@ -0,0 +1,46 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class OrbitalSoftDescriptors
4
+ include Validateable
5
+
6
+ PHONE_FORMAT_1 = /\A\d{3}-\d{3}-\d{4}\z/
7
+ PHONE_FORMAT_2 = /\A\d{3}-\w{7}\z/
8
+
9
+ # ==== Tampa PNS Soft Descriptors
10
+ # The support for Soft Descriptors via the PNS Host is only for customers processing through Chase
11
+ # Paymentech Canada.
12
+
13
+ # Unlike Salem, the only value that gets passed on the cardholder statement is the Merchant Name field.
14
+ # And for these customers, it is a maximum of 25 bytes of data.
15
+ #
16
+ # All other Soft Descriptor fields can optionally be sent, but will not be submitted to the settlement host
17
+ # and will not display on the cardholder statement.
18
+
19
+ attr_accessor :merchant_name, :product_description, :merchant_city, :merchant_phone, :merchant_url, :merchant_email
20
+
21
+ def initialize(options = {})
22
+ self.merchant_name = options[:merchant_name]
23
+ self.merchant_city = options[:merchant_city]
24
+ self.merchant_phone = options[:merchant_phone]
25
+ self.merchant_url = options[:merchant_url]
26
+ self.merchant_email = options[:merchant_email]
27
+ end
28
+
29
+ def validate
30
+ errors.add(:merchant_name, "is required") if self.merchant_name.blank?
31
+ errors.add(:merchant_name, "is required to be 25 bytes or less") if self.merchant_name.bytesize > 25
32
+
33
+ unless self.merchant_phone.blank? || self.merchant_phone.match(PHONE_FORMAT_1) || self.merchant_phone.match(PHONE_FORMAT_2)
34
+ errors.add(:merchant_phone, "is required to follow \"NNN-NNN-NNNN\" or \"NNN-AAAAAAA\" format")
35
+ end
36
+
37
+ [:merchant_email, :merchant_url].each do |attr|
38
+ unless self.send(attr).blank?
39
+ errors.add(attr, "is required to be 13 bytes or less") if self.send(attr).bytesize > 13
40
+ end
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,392 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # PayJunction Gateway
4
+ #
5
+ # This gateway accepts the following arguments:
6
+ # :login => your PayJunction username
7
+ # :password => your PayJunction pass
8
+ #
9
+ # Example use:
10
+ #
11
+ # gateway = ActiveMerchant::Billing::Base.gateway(:pay_junction).new(
12
+ # :login => "my_account",
13
+ # :password => "my_pass"
14
+ # )
15
+ #
16
+ # # set up credit card obj as in main ActiveMerchant example
17
+ # creditcard = ActiveMerchant::Billing::CreditCard.new(
18
+ # :type => 'visa',
19
+ # :number => '4242424242424242',
20
+ # :month => 8,
21
+ # :year => 2009,
22
+ # :first_name => 'Bob',
23
+ # :last_name => 'Bobsen'
24
+ # )
25
+ #
26
+ # # optionally specify address if using AVS
27
+ # address = { :address1 => '101 Test Ave', :city => 'Test', :state => 'TS',
28
+ # :zip => '10101', :country => 'US' }
29
+ #
30
+ # # run request
31
+ # response = gateway.purchase(1000, creditcard, :address => address) # charge 10 dollars
32
+ #
33
+ # 1) Check whether the transaction was successful
34
+ #
35
+ # response.success?
36
+ #
37
+ # 2) Retrieve the message returned by PayJunction
38
+ #
39
+ # response.message
40
+ #
41
+ # 3) Retrieve the unique transaction ID returned by PayJunction
42
+ #
43
+ # response.authorization
44
+ #
45
+ # This gateway supports "instant" transactions. These transactions allow you
46
+ # to execute an operation on a previously run card without card information
47
+ # provided you have the transaction id from a previous transaction with the
48
+ # same card. All functions that take a credit card object for this gateway
49
+ # can take a transaction id string instead.
50
+ #
51
+ # Test Transactions
52
+ #
53
+ # See the source for initialize() for test account information. Note that
54
+ # PayJunction does not allow test transactions on your account, so if the
55
+ # gateway is running in :test mode your transaction will be run against
56
+ # PayJunction's global test account and will not show up in your account.
57
+ #
58
+ # Transactions ran on this account go through a test processor, so there is no
59
+ # need to void or otherwise cancel transactions. However, for further safety,
60
+ # please use the special card numbers 4433221111223344 or 4444333322221111 and
61
+ # keep transaction amounts below $4.00 when testing.
62
+ #
63
+ # Also note, transactions ran for an amount between $0.00 and $1.99 will likely
64
+ # result in denial. To demonstrate approvals, use amounts between $2.00 and $4.00.
65
+ #
66
+ # Test transactions can be checked by logging into
67
+ # PayJunction Web Login with username 'pj-cm-01' and password 'pj-cm-01p'
68
+ #
69
+ # Usage Details
70
+ #
71
+ # Below is a map of values accepted by PayJunction and how you should submit
72
+ # each to ActiveMerchant
73
+ #
74
+ # PayJunction Field ActiveMerchant Use
75
+ #
76
+ # dc_logon provide as :login value to gateway instantation
77
+ # dc_password provide as :password value to gateway instantiation
78
+ #
79
+ # dc_name will be retrieved from credit_card.name
80
+ # dc_first_name :first_name on CreditCard object instantation
81
+ # dc_last_name :last_name on CreditCard object instantation
82
+ # dc_number :number on CreditCard object instantation
83
+ # dc_expiration_month :month on CreditCard object instantation
84
+ # dc_expiration_year :year on CreditCard object instantation
85
+ # dc_verification_number :verification_value on CC object instantation
86
+ #
87
+ # dc_transaction_amount include as argument to method for your transaction type
88
+ # dc_transaction_type do nothing, set by your transaction type
89
+ # dc_version do nothing, always "1.2"
90
+ #
91
+ # dc_transaction_id submit as a string in place of CreditCard obj for
92
+ # "instant" transactions.
93
+ #
94
+ # dc_invoice :order_id in options for transaction method
95
+ # dc_notes :description in options for transaction method
96
+ #
97
+ # See example use above for address AVS fields
98
+ # See #recurring for periodic transaction fields
99
+ class PayJunctionGateway < Gateway
100
+ API_VERSION = '1.2'
101
+
102
+ class_attribute :test_url, :live_url
103
+
104
+ self.test_url = "https://www.payjunctionlabs.com/quick_link"
105
+ self.live_url = "https://payjunction.com/quick_link"
106
+
107
+ TEST_LOGIN = 'pj-ql-01'
108
+ TEST_PASSWORD = 'pj-ql-01p'
109
+
110
+ SUCCESS_CODES = ["00", "85"]
111
+ SUCCESS_MESSAGE = 'The transaction was approved.'
112
+
113
+ FAILURE_MESSAGE = 'The transaction was declined.'
114
+
115
+ DECLINE_CODES = {
116
+ "AE" => 'Address verification failed because address did not match.',
117
+ 'ZE' => 'Address verification failed because zip did not match.',
118
+ 'XE' => 'Address verification failed because zip and address did not match.',
119
+ 'YE' => 'Address verification failed because zip and address did not match.',
120
+ 'OE' => 'Address verification failed because address or zip did not match.',
121
+ 'UE' => 'Address verification failed because cardholder address unavailable.',
122
+ 'RE' => 'Address verification failed because address verification system is not working.',
123
+ 'SE' => 'Address verification failed because address verification system is unavailable.',
124
+ 'EE' => 'Address verification failed because transaction is not a mail or phone order.',
125
+ 'GE' => 'Address verification failed because international support is unavailable.',
126
+ 'CE' => 'Declined because CVV2/CVC2 code did not match.',
127
+ '04' => 'Declined. Pick up card.',
128
+ '07' => 'Declined. Pick up card (Special Condition).',
129
+ '41' => 'Declined. Pick up card (Lost).',
130
+ '43' => 'Declined. Pick up card (Stolen).',
131
+ '13' => 'Declined because of the amount is invalid.',
132
+ '14' => 'Declined because the card number is invalid.',
133
+ '80' => 'Declined because of an invalid date.',
134
+ '05' => 'Declined. Do not honor.',
135
+ '51' => 'Declined because of insufficient funds.',
136
+ 'N4' => 'Declined because the amount exceeds issuer withdrawal limit.',
137
+ '61' => 'Declined because the amount exceeds withdrawal limit.',
138
+ '62' => 'Declined because of an invalid service code (restricted).',
139
+ '65' => 'Declined because the card activity limit exceeded.',
140
+ '93' => 'Declined because there a violation (the transaction could not be completed).',
141
+ '06' => 'Declined because address verification failed.',
142
+ '54' => 'Declined because the card has expired.',
143
+ '15' => 'Declined because there is no such issuer.',
144
+ '96' => 'Declined because of a system error.',
145
+ 'N7' => 'Declined because of a CVV2/CVC2 mismatch.',
146
+ 'M4' => 'Declined.',
147
+ "FE" => "There was a format error with your Trinity Gateway Service (API) request.",
148
+ "LE" => "Could not log you in (problem with dc_logon and/or dc_password).",
149
+ 'NL' => 'Aborted because of a system error, please try again later. ',
150
+ 'AB' => 'Aborted because of an upstream system error, please try again later.'
151
+ }
152
+
153
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
154
+ self.supported_countries = ['US']
155
+ self.homepage_url = 'http://www.payjunction.com/'
156
+ self.display_name = 'PayJunction'
157
+
158
+ def initialize(options = {})
159
+ requires!(options, :login, :password)
160
+ @options = options
161
+ super
162
+ end
163
+
164
+ # The first half of the preauth(authorize)/postauth(capture) model.
165
+ # Checks to make sure funds are available for a transaction, and returns a
166
+ # transaction_id that can be used later to postauthorize (capture) the funds.
167
+ def authorize(money, payment_source, options = {})
168
+ parameters = {
169
+ :transaction_amount => amount(money),
170
+ }
171
+
172
+ add_payment_source(parameters, payment_source)
173
+ add_address(parameters, options)
174
+ add_optional_fields(parameters, options)
175
+ commit('AUTHORIZATION', parameters)
176
+ end
177
+
178
+ # A simple sale, capturing funds immediately.
179
+ # Execute authorization and capture in a single step.
180
+ def purchase(money, payment_source, options = {})
181
+ parameters = {
182
+ :transaction_amount => amount(money),
183
+ }
184
+
185
+ add_payment_source(parameters, payment_source)
186
+ add_address(parameters, options)
187
+ add_optional_fields(parameters, options)
188
+ commit('AUTHORIZATION_CAPTURE', parameters)
189
+ end
190
+
191
+ # The second half of the preauth(authorize)/postauth(capture) model.
192
+ # Retrieve funds that have been previously authorized with _authorization_
193
+ def capture(money, authorization, options = {})
194
+ parameters = {
195
+ :transaction_id => authorization,
196
+ :posture => 'capture'
197
+ }
198
+
199
+ add_optional_fields(parameters, options)
200
+ commit('update', parameters)
201
+ end
202
+
203
+ # Return money to a card that was previously billed.
204
+ # _authorization_ should be the transaction id of the transaction we are returning.
205
+ def credit(money, authorization, options = {})
206
+ parameters = {
207
+ :transaction_amount => amount(money),
208
+ :transaction_id => authorization
209
+ }
210
+
211
+ commit('CREDIT', parameters)
212
+ end
213
+
214
+ # Cancel a transaction that has been charged but has not yet made it
215
+ # through the batch process.
216
+ def void(authorization, options = {})
217
+ parameters = {
218
+ :transaction_id => authorization,
219
+ :posture => 'void'
220
+ }
221
+
222
+ add_optional_fields(parameters, options)
223
+ commit('update', parameters)
224
+ end
225
+
226
+ # Set up a sale that will be made on a regular basis for the same amount
227
+ # (ex. $20 a month for 12 months)
228
+ #
229
+ # The parameter :periodicity should be specified as either :monthly, :weekly, or :daily
230
+ # The parameter :payments should be the number of payments to be made
231
+ #
232
+ # gateway.recurring('2000', creditcard, :periodicity => :monthly, :payments => 12)
233
+ #
234
+ # The optional parameter :starting_at takes a date or time argument or a string in
235
+ # YYYYMMDD format and can be used to specify when the first charge will be made.
236
+ # If omitted the first charge will be immediate.
237
+ def recurring(money, payment_source, options = {})
238
+ requires!(options, [:periodicity, :monthly, :weekly, :daily], :payments)
239
+
240
+ periodic_type = case options[:periodicity]
241
+ when :monthly
242
+ 'month'
243
+ when :weekly
244
+ 'week'
245
+ when :daily
246
+ 'day'
247
+ end
248
+
249
+ if options[:starting_at].nil?
250
+ start_date = Time.now.strftime('%Y-%m-%d')
251
+ elsif options[:starting_at].is_a?(String)
252
+ sa = options[:starting_at]
253
+ start_date = "#{sa[0..3]}-#{sa[4..5]}-#{sa[6..7]}"
254
+ else
255
+ start_date = options[:starting_at].strftime('%Y-%m-%d')
256
+ end
257
+
258
+ parameters = {
259
+ :transaction_amount => amount(money),
260
+ :schedule_periodic_type => periodic_type,
261
+ :schedule_create => 'true',
262
+ :schedule_limit => options[:payments].to_i > 1 ? options[:payments] : 1,
263
+ :schedule_periodic_number => 1,
264
+ :schedule_start => start_date
265
+ }
266
+
267
+ add_payment_source(parameters, payment_source)
268
+ add_optional_fields(parameters, options)
269
+ add_address(parameters, options)
270
+ commit('AUTHORIZATION_CAPTURE', parameters)
271
+ end
272
+
273
+ def test?
274
+ test_login? || @options[:test] || super
275
+ end
276
+
277
+ private
278
+
279
+ def test_login?
280
+ @options[:login] == TEST_LOGIN && @options[:password] == TEST_PASSWORD
281
+ end
282
+
283
+ # add fields depending on payment source selected (cc or transaction id)
284
+ def add_payment_source(params, source)
285
+ if source.is_a?(String)
286
+ add_billing_id(params, source)
287
+ else
288
+ add_creditcard(params, source)
289
+ end
290
+ end
291
+
292
+ # add fields for credit card
293
+ def add_creditcard(params, creditcard)
294
+ params[:name] = creditcard.name
295
+ params[:number] = creditcard.number
296
+ params[:expiration_month] = creditcard.month
297
+ params[:expiration_year] = creditcard.year
298
+ params[:verification_number] = creditcard.verification_value if creditcard.verification_value?
299
+ end
300
+
301
+ # add field for "instant" transaction, using previous transaction id
302
+ def add_billing_id(params, billingid)
303
+ params[:transaction_id] = billingid
304
+ end
305
+
306
+ # add address fields if present
307
+ def add_address(params, options)
308
+ address = options[:billing_address] || options[:address]
309
+
310
+ if address
311
+ params[:address] = address[:address1] unless address[:address1].blank?
312
+ params[:city] = address[:city] unless address[:city].blank?
313
+ params[:state] = address[:state] unless address[:state].blank?
314
+ params[:zipcode] = address[:zip] unless address[:zip].blank?
315
+ params[:country] = address[:country] unless address[:country].blank?
316
+ end
317
+ end
318
+
319
+ def add_optional_fields(params, options)
320
+ params[:notes] = options[:description] unless options[:description].blank?
321
+ params[:invoice] = options[:order_id].to_s.gsub(/[^-\/\w.,']/, '') unless options[:order_id].blank?
322
+ end
323
+
324
+ def commit(action, parameters)
325
+ url = test? ? self.test_url : self.live_url
326
+
327
+ response = parse( ssl_post(url, post_data(action, parameters)) )
328
+
329
+ Response.new(successful?(response), message_from(response), response,
330
+ :test => test?,
331
+ :authorization => response[:transaction_id] || parameters[:transaction_id]
332
+ )
333
+ end
334
+
335
+ def successful?(response)
336
+ SUCCESS_CODES.include?(response[:response_code]) || response[:query_status] == true
337
+ end
338
+
339
+ def message_from(response)
340
+ if successful?(response)
341
+ SUCCESS_MESSAGE
342
+ else
343
+ DECLINE_CODES[response[:response_code]] || FAILURE_MESSAGE
344
+ end
345
+ end
346
+
347
+ def post_data(action, params)
348
+ if test?
349
+ # test requests must use global test account
350
+ params[:logon] = TEST_LOGIN
351
+ params[:password] = TEST_PASSWORD
352
+ else
353
+ params[:logon] = @options[:login]
354
+ params[:password] = @options[:password]
355
+ end
356
+ params[:version] = API_VERSION
357
+ params[:transaction_type] = action
358
+
359
+ params.reject{|k,v| v.blank?}.collect{ |k, v| "dc_#{k.to_s}=#{CGI.escape(v.to_s)}" }.join("&")
360
+ end
361
+
362
+ def parse(body)
363
+ # PayJunction uses the Field Separator ASCII character to separate key/val
364
+ # pairs in the response. The <FS> character's octal value is 034.
365
+ #
366
+ # Sample response:
367
+ #
368
+ # transaction_id=44752<FS>response_code=M4<FS>response_message=Declined (INV TEST CARD).
369
+
370
+ pairs = body.chomp.split("\034")
371
+ response = {}
372
+ pairs.each do |pair|
373
+ key, val = pair.split('=')
374
+ response[key[3..-1].to_sym] = val ? normalize(val) : nil
375
+ end
376
+ response
377
+ end
378
+
379
+ # Make a ruby type out of the response string
380
+ def normalize(field)
381
+ case field
382
+ when "true" then true
383
+ when "false" then false
384
+ when "" then nil
385
+ when "null" then nil
386
+ else field
387
+ end
388
+ end
389
+
390
+ end
391
+ end
392
+ end