aktivemerchant 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1596 -0
  3. data/CONTRIBUTORS +511 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +18 -0
  6. data/lib/active_merchant.rb +108 -0
  7. data/lib/active_merchant/billing.rb +13 -0
  8. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  9. data/lib/active_merchant/billing/avs_result.rb +98 -0
  10. data/lib/active_merchant/billing/base.rb +72 -0
  11. data/lib/active_merchant/billing/check.rb +76 -0
  12. data/lib/active_merchant/billing/compatibility.rb +120 -0
  13. data/lib/active_merchant/billing/credit_card.rb +352 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +160 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +268 -0
  18. data/lib/active_merchant/billing/gateways.rb +17 -0
  19. data/lib/active_merchant/billing/gateways/adyen.rb +209 -0
  20. data/lib/active_merchant/billing/gateways/alfabank.rb +117 -0
  21. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net.rb +419 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  24. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  25. data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
  26. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  27. data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
  28. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
  29. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
  30. data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
  31. data/lib/active_merchant/billing/gateways/beanstream.rb +188 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +393 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  34. data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
  35. data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
  36. data/lib/active_merchant/billing/gateways/borgun.rb +210 -0
  37. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  38. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +515 -0
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  42. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  43. data/lib/active_merchant/billing/gateways/card_stream.rb +220 -0
  44. data/lib/active_merchant/billing/gateways/cashnet.rb +191 -0
  45. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  46. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  47. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  48. data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
  49. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  50. data/lib/active_merchant/billing/gateways/conekta.rb +209 -0
  51. data/lib/active_merchant/billing/gateways/cyber_source.rb +709 -0
  52. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  53. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  54. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  55. data/lib/active_merchant/billing/gateways/epay.rb +275 -0
  56. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  57. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  58. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  59. data/lib/active_merchant/billing/gateways/eway_rapid.rb +524 -0
  60. data/lib/active_merchant/billing/gateways/exact.rb +218 -0
  61. data/lib/active_merchant/billing/gateways/fat_zebra.rb +173 -0
  62. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  63. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  64. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  65. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  66. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +355 -0
  67. data/lib/active_merchant/billing/gateways/garanti.rb +257 -0
  68. data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
  69. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  70. data/lib/active_merchant/billing/gateways/hps.rb +288 -0
  71. data/lib/active_merchant/billing/gateways/iats_payments.rb +251 -0
  72. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  73. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  74. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  75. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  76. data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
  77. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  78. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  79. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  80. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  81. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  82. data/lib/active_merchant/billing/gateways/litle.rb +346 -0
  83. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  84. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  85. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  86. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  87. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  88. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  89. data/lib/active_merchant/billing/gateways/mercury.rb +333 -0
  90. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  91. data/lib/active_merchant/billing/gateways/migs.rb +265 -0
  92. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  93. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  94. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  95. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  96. data/lib/active_merchant/billing/gateways/moneris_us.rb +291 -0
  97. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  98. data/lib/active_merchant/billing/gateways/nab_transact.rb +280 -0
  99. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  100. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  101. data/lib/active_merchant/billing/gateways/netbilling.rb +190 -0
  102. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  103. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  104. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  105. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  106. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  107. data/lib/active_merchant/billing/gateways/optimal_payment.rb +313 -0
  108. data/lib/active_merchant/billing/gateways/orbital.rb +803 -0
  109. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  110. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  111. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  112. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +261 -0
  113. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  114. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  115. data/lib/active_merchant/billing/gateways/pay_u_latam.rb +462 -0
  116. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  117. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  118. data/lib/active_merchant/billing/gateways/payflow.rb +304 -0
  119. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +209 -0
  120. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  121. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  122. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  123. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  124. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  125. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  126. data/lib/active_merchant/billing/gateways/paymill.rb +281 -0
  127. data/lib/active_merchant/billing/gateways/paypal.rb +117 -0
  128. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +670 -0
  129. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  130. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  131. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  132. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  133. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  134. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  135. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  136. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  137. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  138. data/lib/active_merchant/billing/gateways/pin.rb +197 -0
  139. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  140. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  141. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  142. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  143. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  144. data/lib/active_merchant/billing/gateways/quickpay.rb +367 -0
  145. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  146. data/lib/active_merchant/billing/gateways/redsys.rb +391 -0
  147. data/lib/active_merchant/billing/gateways/sage.rb +175 -0
  148. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +87 -0
  149. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +114 -0
  150. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  151. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +102 -0
  152. data/lib/active_merchant/billing/gateways/sage_pay.rb +398 -0
  153. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  154. data/lib/active_merchant/billing/gateways/secure_net.rb +252 -0
  155. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  156. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  157. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  158. data/lib/active_merchant/billing/gateways/skip_jack.rb +452 -0
  159. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  160. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  161. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  162. data/lib/active_merchant/billing/gateways/stripe.rb +411 -0
  163. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  164. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  165. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  166. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  167. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  168. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  169. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  170. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  171. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +254 -0
  172. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  173. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  174. data/lib/active_merchant/billing/gateways/vindicia.rb +385 -0
  175. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  176. data/lib/active_merchant/billing/gateways/wepay.rb +189 -0
  177. data/lib/active_merchant/billing/gateways/wirecard.rb +421 -0
  178. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  179. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  180. data/lib/active_merchant/billing/model.rb +30 -0
  181. data/lib/active_merchant/billing/payment_token.rb +21 -0
  182. data/lib/active_merchant/billing/rails.rb +3 -0
  183. data/lib/active_merchant/billing/response.rb +91 -0
  184. data/lib/active_merchant/country.rb +332 -0
  185. data/lib/active_merchant/empty.rb +20 -0
  186. data/lib/active_merchant/errors.rb +29 -0
  187. data/lib/active_merchant/offsite_payments_shim.rb +19 -0
  188. data/lib/active_merchant/version.rb +3 -0
  189. data/lib/activemerchant.rb +1 -0
  190. data/lib/support/gateway_support.rb +71 -0
  191. data/lib/support/outbound_hosts.rb +25 -0
  192. data/lib/support/ssl_verify.rb +93 -0
  193. metadata +400 -0
@@ -0,0 +1,157 @@
1
+ require 'json'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class SwipeCheckoutGateway < Gateway
6
+ TRANSACTION_APPROVED_MSG = 'Transaction approved'
7
+ TRANSACTION_DECLINED_MSG = 'Transaction declined'
8
+
9
+ LIVE_URLS = {
10
+ 'NZ' => 'https://api.swipehq.com',
11
+ 'CA' => 'https://api.swipehq.ca'
12
+ }
13
+ self.test_url = 'https://api.swipehq.com'
14
+
15
+ TRANSACTION_API = '/createShopifyTransaction.php'
16
+
17
+ self.supported_countries = %w[ NZ CA ]
18
+ self.default_currency = 'NZD'
19
+ self.supported_cardtypes = [:visa, :master]
20
+ self.homepage_url = 'https://www.swipehq.com/checkout'
21
+ self.display_name = 'Swipe Checkout'
22
+ self.money_format = :dollars
23
+
24
+ # Swipe Checkout requires the merchant's email and API key for authorization.
25
+ # This can be found under Settings > API Credentials after logging in to your
26
+ # Swipe Checkout merchant console at https://merchant.swipehq.[com|ca]
27
+ #
28
+ # :region determines which Swipe URL is used, this can be one of "NZ" or "CA".
29
+ # Currently Swipe Checkout has New Zealand and Canadian domains (swipehq.com
30
+ # and swipehq.ca respectively). Merchants must use the region that they
31
+ # signed up in for authentication with their merchant ID and API key to succeed.
32
+ def initialize(options = {})
33
+ requires!(options, :login, :api_key, :region)
34
+ super
35
+ end
36
+
37
+ # Transfers funds immediately.
38
+ # Note that Swipe Checkout only supports purchase at this stage
39
+ def purchase(money, creditcard, options = {})
40
+ post = {}
41
+ add_invoice(post, options)
42
+ add_creditcard(post, creditcard)
43
+ add_customer_data(post, creditcard, options)
44
+ add_amount(post, money, options)
45
+
46
+ commit('sale', money, post)
47
+ end
48
+
49
+ private
50
+
51
+ def add_customer_data(post, creditcard, options)
52
+ post[:email] = options[:email]
53
+ post[:ip_address] = options[:ip]
54
+
55
+ address = options[:billing_address] || options[:address]
56
+ return if address.nil?
57
+
58
+ post[:company] = address[:company]
59
+
60
+ # groups all names after the first into the last name param
61
+ post[:first_name], post[:last_name] = address[:name].split(' ', 2)
62
+ post[:address] = "#{address[:address1]}, #{address[:address2]}"
63
+ post[:city] = address[:city]
64
+ post[:country] = address[:country]
65
+ post[:mobile] = address[:phone] # API only has a "mobile" field, no "phone"
66
+ end
67
+
68
+ def add_invoice(post, options)
69
+ # store shopping-cart order ID in Swipe for merchant's records
70
+ post[:td_user_data] = options[:order_id] if options[:order_id]
71
+ post[:td_item] = options[:description] if options[:description]
72
+ post[:td_description] = options[:description] if options[:description]
73
+ post[:item_quantity] = "1"
74
+ end
75
+
76
+ def add_creditcard(post, creditcard)
77
+ post[:card_number] = creditcard.number
78
+ post[:card_type] = creditcard.brand
79
+ post[:name_on_card] = "#{creditcard.first_name} #{creditcard.last_name}"
80
+ post[:card_expiry] = expdate(creditcard)
81
+ post[:secure_number] = creditcard.verification_value
82
+ end
83
+
84
+ def expdate(creditcard)
85
+ year = format(creditcard.year, :two_digits)
86
+ month = format(creditcard.month, :two_digits)
87
+
88
+ "#{month}#{year}"
89
+ end
90
+
91
+ def add_amount(post, money, options)
92
+ post[:amount] = money.to_s
93
+
94
+ post[:currency] = (options[:currency] || currency(money))
95
+ end
96
+
97
+ def commit(action, money, parameters)
98
+ case action
99
+ when "sale"
100
+ begin
101
+ response = call_api(TRANSACTION_API, parameters)
102
+
103
+ # response code and message params should always be present
104
+ code = response["response_code"]
105
+ message = response["message"]
106
+
107
+ if code == 200
108
+ result = response["data"]["result"]
109
+ success = (result == 'accepted' || (test? && result == 'test-accepted'))
110
+
111
+ Response.new(success,
112
+ success ?
113
+ TRANSACTION_APPROVED_MSG :
114
+ TRANSACTION_DECLINED_MSG,
115
+ response,
116
+ :test => test?
117
+ )
118
+ else
119
+ build_error_response(message, response)
120
+ end
121
+ rescue ResponseError => e
122
+ build_error_response("ssl_post() with url #{url} raised ResponseError: #{e}")
123
+ rescue JSON::ParserError => e
124
+ msg = 'Invalid response received from the Swipe Checkout API. ' +
125
+ 'Please contact support@optimizerhq.com if you continue to receive this message.' +
126
+ " (Full error message: #{e})"
127
+ build_error_response(msg)
128
+ end
129
+ end
130
+ end
131
+
132
+ def call_api(api, params=nil)
133
+ params ||= {}
134
+ params[:merchant_id] = @options[:login]
135
+ params[:api_key] = @options[:api_key]
136
+
137
+ # ssl_post() returns the response body as a string on success,
138
+ # or raises a ResponseError exception on failure
139
+ JSON.parse(ssl_post(url(@options[:region], api), params.to_query))
140
+ end
141
+
142
+ def url(region, api)
143
+ ((test? ? self.test_url : LIVE_URLS[region]) + api)
144
+ end
145
+
146
+ def build_error_response(message, params={})
147
+ Response.new(
148
+ false,
149
+ message,
150
+ params,
151
+ :test => test?
152
+ )
153
+ end
154
+ end
155
+ end
156
+ end
157
+
@@ -0,0 +1,227 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class TnsGateway < Gateway
4
+ self.display_name = 'TNS'
5
+ self.homepage_url = 'http://www.tnsi.com/'
6
+
7
+ # Testing is partitioned by account.
8
+ self.live_url = 'https://secure.na.tnspayments.com/api/rest/version/22/'
9
+
10
+ self.supported_countries = %w(AR AU BR FR DE HK MX NZ SG GB US)
11
+
12
+ self.default_currency = 'USD'
13
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro, :laser]
14
+
15
+ def initialize(options={})
16
+ requires!(options, :userid, :password)
17
+ super
18
+ end
19
+
20
+ def purchase(amount, payment_method, options={})
21
+ MultiResponse.run do |r|
22
+ r.process { authorize(amount, payment_method, options) }
23
+ r.process { capture(amount, r.authorization, options) }
24
+ end
25
+ end
26
+
27
+ def authorize(amount, payment_method, options={})
28
+ post = new_post
29
+ add_invoice(post, amount, options)
30
+ add_reference(post, *new_authorization)
31
+ add_payment_method(post, payment_method)
32
+ add_customer_data(post, options)
33
+
34
+ commit('authorize', post)
35
+ end
36
+
37
+ def capture(amount, authorization, options={})
38
+ post = new_post
39
+ add_invoice(post, amount, options, :transaction)
40
+ add_reference(post, *next_authorization(authorization))
41
+ add_customer_data(post, options)
42
+
43
+ commit('capture', post)
44
+ end
45
+
46
+ def refund(amount, authorization, options={})
47
+ post = new_post
48
+ add_invoice(post, amount, options, :transaction)
49
+ add_reference(post, *next_authorization(authorization))
50
+ add_customer_data(post, options)
51
+
52
+ commit('refund', post)
53
+ end
54
+
55
+ def void(authorization, options={})
56
+ post = new_post
57
+ add_reference(post, *next_authorization(authorization), :targetTransactionId)
58
+
59
+ commit('void', post)
60
+ end
61
+
62
+ def verify(credit_card, options={})
63
+ MultiResponse.run(:use_first_response) do |r|
64
+ r.process { authorize(100, credit_card, options) }
65
+ r.process(:ignore_result) { void(r.authorization, options) }
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def new_post
72
+ {
73
+ order: {},
74
+ sourceOfFunds: {
75
+ provided: {
76
+ card: {
77
+ }
78
+ }
79
+ },
80
+ customer: {},
81
+ billing: {},
82
+ shipping: {},
83
+ transaction: {},
84
+ }
85
+ end
86
+
87
+ def add_invoice(post, amount, options, node=:order)
88
+ post[node][:amount] = amount(amount)
89
+ post[node][:currency] = (options[:currency] || currency(amount))
90
+ end
91
+
92
+ def add_reference(post, orderid, transactionid, transaction_reference, reference_key=:reference)
93
+ post[:orderid] = orderid
94
+ post[:transactionid] = transactionid
95
+ post[:transaction][reference_key] = transaction_reference if transaction_reference
96
+ end
97
+
98
+ def add_payment_method(post, payment_method)
99
+ card = {}
100
+ card[:expiry] = {}
101
+ card[:number] = payment_method.number
102
+ card[:securityCode] = payment_method.verification_value
103
+ card[:expiry][:year] = format(payment_method.year, :two_digits)
104
+ card[:expiry][:month] = format(payment_method.month, :two_digits)
105
+
106
+ post[:sourceOfFunds][:type] = 'CARD'
107
+ post[:sourceOfFunds][:provided][:card].merge!(card)
108
+ end
109
+
110
+ def add_customer_data(post, options)
111
+ billing = {}
112
+ shipping = {}
113
+ customer = {}
114
+ if(billing_address = (options[:billing_address] || options[:address]))
115
+ billing[:address] = {}
116
+ billing[:address][:street] = billing_address[:address1]
117
+ billing[:address][:street2] = billing_address[:address2]
118
+ billing[:address][:city] = billing_address[:city]
119
+ billing[:address][:stateProvince] = billing_address[:state]
120
+ billing[:address][:postcodeZip] = billing_address[:zip]
121
+ billing[:address][:country] = billing_address[:country]
122
+ billing[:phone] = billing_address[:phone]
123
+
124
+ customer[:email] = options[:email] if options[:email]
125
+ customer[:ipaddress] = options[:ip] if options[:ip]
126
+ end
127
+
128
+ if(shipping_address = options[:shipping_address])
129
+ shipping[:address] = {}
130
+ shipping[:address][:street] = shipping_address[:address1]
131
+ shipping[:address][:street2] = shipping_address[:address2]
132
+ shipping[:address][:city] = shipping_address[:city]
133
+ shipping[:address][:stateProvince] = shipping_address[:state]
134
+ shipping[:address][:postcodeZip] = shipping_address[:zip]
135
+ shipping[:address][:shipcountry] = shipping_address[:country]
136
+
137
+ last_name, first_middle_names = split_name(shipping_address[:name])
138
+ shipping[:firstName] = first_middle_names if first_middle_names
139
+ shipping[:lastName] = last_name if last_name
140
+ end
141
+ post[:billing].merge!(billing)
142
+ post[:shipping].merge!(shipping)
143
+ post[:customer].merge!(customer)
144
+ end
145
+
146
+ def commit(action, post)
147
+ url = build_url(post.delete(:orderid), post.delete(:transactionid))
148
+ headers = {
149
+ 'Authorization' => 'Basic ' + Base64.encode64("merchant.#{@options[:userid]}:#{@options[:password]}").strip.delete("\r\n"),
150
+ 'Content-Type' => 'application/json',
151
+ }
152
+ post[:apiOperation] = action.upcase
153
+ raw = parse(ssl_request(:put, url, build_request(post), headers))
154
+
155
+ succeeded = success_from(raw['result'])
156
+ Response.new(
157
+ succeeded,
158
+ message_from(succeeded, raw),
159
+ raw,
160
+ :authorization => authorization_from(post, raw),
161
+ :test => test?
162
+ )
163
+ end
164
+
165
+ def build_url(orderid, transactionid)
166
+ "#{live_url}merchant/#{@options[:userid]}/order/#{orderid}/transaction/#{transactionid}"
167
+ end
168
+
169
+ def build_request(post = {})
170
+ post.to_json
171
+ end
172
+
173
+ def parse(body)
174
+ JSON.parse(body)
175
+ end
176
+
177
+ def success_from(response)
178
+ response == 'SUCCESS'
179
+ end
180
+
181
+ def message_from(succeeded, response)
182
+ if succeeded
183
+ 'Succeeded'
184
+ else
185
+ [
186
+ response['result'],
187
+ response['response'] && response['response']['gatewayCode'],
188
+ response['error'] && response['error']['cause'],
189
+ response['error'] && response['error']['explanation']
190
+ ].compact.join(' - ')
191
+ end
192
+ end
193
+
194
+ def authorization_from(request, response)
195
+ [response['order']['id'], response['transaction']['id']].join('|') if response['order']
196
+ end
197
+
198
+ def split_authorization(authorization)
199
+ authorization.split('|')
200
+ end
201
+
202
+ def new_authorization
203
+ # Must be unique within a merchant id.
204
+ orderid = SecureRandom.uuid
205
+
206
+ # Must be unique within an order id.
207
+ transactionid = '1'
208
+
209
+ # New transactions have no previous reference.
210
+ transaction_reference = nil
211
+ [orderid, transactionid, transaction_reference]
212
+ end
213
+
214
+ def next_authorization(authorization)
215
+ orderid, prev_transactionid = split_authorization(authorization)
216
+ next_transactionid = SecureRandom.uuid
217
+ [orderid, next_transactionid, prev_transactionid]
218
+ end
219
+
220
+ def split_name(full_name)
221
+ return nil unless full_name
222
+ names = full_name.split
223
+ [names.pop, names.join(' ')]
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,126 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class TransFirstGateway < Gateway
4
+ self.live_url = self.test_url = 'https://webservices.primerchants.com/creditcard.asmx/CCSale'
5
+
6
+ self.supported_countries = ['US']
7
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
8
+ self.homepage_url = 'http://www.transfirst.com/'
9
+ self.display_name = 'TransFirst'
10
+
11
+ UNUSED_FIELDS = %w(ECIValue UserId CAVVData TrackData POSInd EComInd MerchZIP MerchCustPNum MCC InstallmentNum InstallmentOf POSEntryMode POSConditionCode AuthCharInd CardCertData)
12
+
13
+ DECLINED = 'The transaction was declined'
14
+
15
+ def initialize(options = {})
16
+ requires!(options, :login, :password)
17
+ super
18
+ end
19
+
20
+ def purchase(money, credit_card, options = {})
21
+ post = {}
22
+
23
+ add_amount(post, money)
24
+ add_invoice(post, options)
25
+ add_credit_card(post, credit_card)
26
+ add_address(post, options)
27
+
28
+ commit(post)
29
+ end
30
+
31
+ private
32
+ def add_amount(post, money)
33
+ add_pair(post, :Amount, amount(money), :required => true)
34
+ end
35
+
36
+ def add_address(post, options)
37
+ address = options[:billing_address] || options[:address]
38
+
39
+ if address
40
+ add_pair(post, :Address, address[:address1])
41
+ add_pair(post, :ZipCode, address[:zip])
42
+ end
43
+ end
44
+
45
+ def add_invoice(post, options)
46
+ add_pair(post, :RefID, options[:order_id], :required => true)
47
+ add_pair(post, :PONumber, options[:invoice], :required => true)
48
+ add_pair(post, :SaleTaxAmount, amount(options[:tax] || 0))
49
+ add_pair(post, :PaymentDesc, options[:description], :required => true)
50
+ add_pair(post, :TaxIndicator, 0)
51
+ end
52
+
53
+ def add_credit_card(post, credit_card)
54
+ add_pair(post, :CardHolderName, credit_card.name, :required => true)
55
+ add_pair(post, :CardNumber, credit_card.number, :required => true)
56
+
57
+ add_pair(post, :Expiration, expdate(credit_card), :required => true)
58
+ add_pair(post, :CVV2, credit_card.verification_value)
59
+ end
60
+
61
+ def add_unused_fields(post)
62
+ UNUSED_FIELDS.each do |f|
63
+ post[f] = ""
64
+ end
65
+ end
66
+
67
+ def expdate(credit_card)
68
+ year = format(credit_card.year, :two_digits)
69
+ month = format(credit_card.month, :two_digits)
70
+
71
+ "#{month}#{year}"
72
+ end
73
+
74
+ def parse(data)
75
+ response = {}
76
+
77
+ xml = REXML::Document.new(data)
78
+ root = REXML::XPath.first(xml, "//CCSaleDebitResponse")
79
+
80
+ if root.nil?
81
+ response[:message] = data.to_s.strip
82
+ else
83
+ root.elements.to_a.each do |node|
84
+ response[node.name.underscore.to_sym] = node.text
85
+ end
86
+ end
87
+
88
+ response
89
+ end
90
+
91
+ def commit(params)
92
+ response = parse( ssl_post(self.live_url, post_data(params)) )
93
+
94
+ Response.new(response[:status] == "Authorized", message_from(response), response,
95
+ :test => test?,
96
+ :authorization => response[:trans_id],
97
+ :avs_result => { :code => response[:avs_code] },
98
+ :cvv_result => response[:cvv2_code]
99
+ )
100
+ end
101
+
102
+ def message_from(response)
103
+ case response[:message]
104
+ when 'Call Voice Center'
105
+ DECLINED
106
+ else
107
+ response[:message]
108
+ end
109
+ end
110
+
111
+ def post_data(params = {})
112
+ add_unused_fields(params)
113
+ params[:MerchantID] = @options[:login]
114
+ params[:RegKey] = @options[:password]
115
+
116
+ request = params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
117
+ request
118
+ end
119
+
120
+ def add_pair(post, key, value, options = {})
121
+ post[key] = value if !value.blank? || options[:required]
122
+ end
123
+ end
124
+ end
125
+ end
126
+