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,23 @@
1
+ require File.dirname(__FILE__) + '/cc5'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class FinansbankGateway < CC5Gateway
6
+ self.live_url = 'https://www.fbwebpos.com/servlet/cc5ApiServer'
7
+ self.test_url = 'https://entegrasyon.asseco-see.com.tr/fim/api'
8
+
9
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
10
+ self.supported_countries = ['US', 'TR']
11
+
12
+ # The card types supported by the payment gateway
13
+ self.supported_cardtypes = [:visa, :master]
14
+
15
+ # The homepage URL of the gateway
16
+ self.homepage_url = 'https://www.fbwebpos.com/'
17
+
18
+ # The name of the gateway
19
+ self.display_name = 'Finansbank WebPOS'
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,143 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class FirstGivingGateway < Gateway
6
+ self.test_url = 'http://usapisandbox.fgdev.net'
7
+ self.live_url = 'https://api.firstgiving.com'
8
+
9
+ self.supported_countries = ['US']
10
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
11
+ self.homepage_url = 'http://www.firstgiving.com/'
12
+ self.default_currency = 'USD'
13
+ self.display_name = 'FirstGiving'
14
+
15
+ def initialize(options = {})
16
+ requires!(options, :application_key, :security_token, :charity_id)
17
+ super
18
+ end
19
+
20
+ def purchase(money, creditcard, options = {})
21
+ post = {}
22
+ add_invoice(post, options)
23
+ add_creditcard(post, creditcard)
24
+ add_address(post, options)
25
+ add_customer_data(post, options)
26
+ add_donation_data(post, money, options)
27
+ commit('/donation/creditcard', post)
28
+ end
29
+
30
+ def refund(money, identifier, options = {})
31
+ get = {}
32
+ get[:transactionId] = identifier
33
+ get[:tranType] = 'REFUNDREQUEST'
34
+ commit("/transaction/refundrequest?" + encode(get))
35
+ end
36
+
37
+ private
38
+
39
+ def add_donation_data(post, money, options)
40
+ post[:amount] = amount(money)
41
+ post[:charityId] = @options[:charity_id]
42
+ post[:description] = (options[:description] || "Purchase")
43
+ post[:currencyCode] = (options[:currency] || currency(money))
44
+ end
45
+
46
+ def add_customer_data(post, options)
47
+ post[:billToEmail] = (options[:email] || "activemerchant@example.com")
48
+ post[:remoteAddr] = (options[:ip] || "127.0.0.1")
49
+ end
50
+
51
+ def add_address(post, options)
52
+ if(billing_address = (options[:billing_address] || options[:address]))
53
+ post[:billToAddressLine1] = billing_address[:address1]
54
+ post[:billToCity] = billing_address[:city]
55
+ post[:billToState] = billing_address[:state]
56
+ post[:billToZip] = billing_address[:zip]
57
+ post[:billToCountry] = billing_address[:country]
58
+ end
59
+ end
60
+
61
+ def add_invoice(post, options)
62
+ post[:orderId] = options[:order_id]
63
+ end
64
+
65
+ def add_creditcard(post, creditcard)
66
+ post[:billToFirstName] = creditcard.first_name
67
+ post[:billToLastName] = creditcard.last_name
68
+ post[:ccNumber] = creditcard.number
69
+ post[:ccType] = creditcard_brand(creditcard.brand)
70
+ post[:ccExpDateMonth] = creditcard.month
71
+ post[:ccExpDateYear] = creditcard.year
72
+ post[:ccCardValidationNum] = creditcard.verification_value
73
+ end
74
+
75
+ def parse(body)
76
+ response = {}
77
+
78
+ xml = Nokogiri::XML(body)
79
+ element = xml.xpath("//firstGivingDonationApi/firstGivingResponse").first
80
+
81
+ element.attributes.each do |name, attribute|
82
+ response[name] = attribute.content
83
+ end
84
+ element.children.each do |child|
85
+ next if child.text?
86
+ response[child.name] = child.text
87
+ end
88
+
89
+ response
90
+ end
91
+
92
+ def commit(action, post=nil)
93
+ url = (test? ? self.test_url : self.live_url) + action
94
+
95
+ begin
96
+ if post
97
+ response = parse(ssl_post(url, post_data(post), headers))
98
+ else
99
+ response = parse(ssl_get(url, headers))
100
+ end
101
+ rescue ResponseError => e
102
+ response = parse(e.response.body)
103
+ end
104
+
105
+ Response.new(
106
+ (response["acknowledgement"] == "Success"),
107
+ (response["friendlyErrorMessage"] || response["verboseErrorMessage"] || response["acknowledgement"]),
108
+ response,
109
+ authorization: response["transactionId"],
110
+ test: test?,
111
+ )
112
+ end
113
+
114
+ def post_data(post)
115
+ post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
116
+ end
117
+
118
+ def encode(hash)
119
+ hash.collect{|(k,v)| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join('&')
120
+ end
121
+
122
+ def creditcard_brand(brand)
123
+ case brand
124
+ when "visa" then "VI"
125
+ when "master" then "MC"
126
+ when "discover" then "DI"
127
+ when "american_express" then "AX"
128
+ else
129
+ raise "Unhandled credit card brand #{brand}"
130
+ end
131
+ end
132
+
133
+ def headers
134
+ {
135
+ "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
136
+ "JG_APPLICATIONKEY" => "#{@options[:application_key]}",
137
+ "JG_SECURITYTOKEN" => "#{@options[:security_token]}"
138
+ }
139
+ end
140
+ end
141
+ end
142
+ end
143
+
@@ -0,0 +1,160 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class FirstPayGateway < Gateway
6
+ self.live_url = 'https://secure.1stpaygateway.net/secure/gateway/xmlgateway.aspx'
7
+
8
+ self.supported_countries = ['US']
9
+ self.default_currency = 'USD'
10
+ self.money_format = :dollars
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
+
13
+ self.homepage_url = 'http://1stpaygateway.net/'
14
+ self.display_name = '1stPayGateway.Net'
15
+
16
+ def initialize(options={})
17
+ requires!(options, :transaction_center_id, :gateway_id)
18
+ super
19
+ end
20
+
21
+ def purchase(money, payment, options={})
22
+ post = {}
23
+ add_invoice(post, money, options)
24
+ add_payment(post, payment)
25
+ add_address(post, payment, options)
26
+ add_customer_data(post, options)
27
+
28
+ commit('sale', post)
29
+ end
30
+
31
+ def authorize(money, payment, options={})
32
+ post = {}
33
+ add_invoice(post, money, options)
34
+ add_payment(post, payment)
35
+ add_address(post, payment, options)
36
+ add_customer_data(post, options)
37
+
38
+ commit('auth', post)
39
+ end
40
+
41
+ def capture(money, authorization, options={})
42
+ post = {}
43
+ add_reference(post, 'settle', money, authorization)
44
+ commit('settle', post)
45
+ end
46
+
47
+ def refund(money, authorization, options={})
48
+ post = {}
49
+ add_reference(post, 'credit', money, authorization)
50
+ commit('credit', post)
51
+ end
52
+
53
+ def void(authorization, options={})
54
+ post = {}
55
+ add_reference(post, 'void', nil, authorization)
56
+ commit('void', post)
57
+ end
58
+
59
+ private
60
+
61
+ def add_authentication(post, options)
62
+ post[:transaction_center_id] = options[:transaction_center_id]
63
+ post[:gateway_id] = options[:gateway_id]
64
+ end
65
+
66
+ def add_customer_data(post, options)
67
+ post[:owner_email] = options[:email] if options[:email]
68
+ post[:remote_ip_address] = options[:ip] if options[:ip]
69
+ end
70
+
71
+ def add_address(post, creditcard, options)
72
+ address = options[:billing_address] || options[:address]
73
+ post[:owner_name] = address[:name]
74
+ post[:owner_street] = address[:address1]
75
+ post[:owner_street2] = address[:address2] if address[:address2]
76
+ post[:owner_city] = address[:city]
77
+ post[:owner_state] = address[:state]
78
+ post[:owner_zip] = address[:zip]
79
+ post[:owner_country] = address[:country]
80
+ post[:owner_phone] = address[:phone] if address[:phone]
81
+ end
82
+
83
+ def add_invoice(post, money, options)
84
+ post[:order_id] = options[:order_id]
85
+ post[:total] = amount(money)
86
+ end
87
+
88
+ def add_payment(post, payment)
89
+ post[:card_name] = payment.brand # Unclear if need to map to known names or open text field??
90
+ post[:card_number] = payment.number
91
+ post[:card_exp] = expdate(payment)
92
+ post[:cvv2] = payment.verification_value
93
+ end
94
+
95
+ def add_reference(post, action, money, authorization)
96
+ post[:"#{action}_amount1"] = amount(money) if money
97
+ post[:total_number_transactions] = 1
98
+ post[:reference_number1] = authorization
99
+ end
100
+
101
+ def parse(xml)
102
+ response = {}
103
+
104
+ doc = Nokogiri::XML(xml)
105
+ doc.root.xpath("//RESPONSE/FIELDS/FIELD").each do |field|
106
+ response[field['KEY']] = field.text
107
+ end unless doc.root.nil?
108
+
109
+ response
110
+ end
111
+
112
+ def commit(action, parameters)
113
+ response = parse(ssl_post(live_url, post_data(action, parameters)))
114
+
115
+ Response.new(
116
+ success_from(response),
117
+ message_from(response),
118
+ response,
119
+ authorization: authorization_from(response),
120
+ test: test?
121
+ )
122
+ end
123
+
124
+ def success_from(response)
125
+ (
126
+ (response['status'] == '1') ||
127
+ (response['status1'] == '1')
128
+ )
129
+ end
130
+
131
+ def message_from(response)
132
+ # Silly inconsistent gateway. Always make capitalized (but not all caps)
133
+ msg = (response['auth_response'] || response['response1'])
134
+ msg.downcase.capitalize if msg
135
+ end
136
+
137
+ def authorization_from(response)
138
+ response['reference_number'] || response['reference_number1']
139
+ end
140
+
141
+ def post_data(action, parameters = {})
142
+ parameters[:transaction_center_id] = @options[:transaction_center_id]
143
+ parameters[:gateway_id] = @options[:gateway_id]
144
+
145
+ parameters[:operation_type] = action
146
+
147
+ xml = Builder::XmlMarkup.new
148
+ xml.instruct!
149
+ xml.tag! 'TRANSACTION' do
150
+ xml.tag! 'FIELDS' do
151
+ parameters.each do |key, value|
152
+ xml.tag! 'FIELD', value, { 'KEY' => key }
153
+ end
154
+ end
155
+ end
156
+ xml.target!
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,355 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class FirstdataE4Gateway < Gateway
4
+ # TransArmor support requires v11 or lower
5
+ self.test_url = "https://api.demo.globalgatewaye4.firstdata.com/transaction/v11"
6
+ self.live_url = "https://api.globalgatewaye4.firstdata.com/transaction/v11"
7
+
8
+ TRANSACTIONS = {
9
+ sale: "00",
10
+ authorization: "01",
11
+ verify: "05",
12
+ capture: "32",
13
+ void: "33",
14
+ credit: "34",
15
+ store: "05"
16
+ }
17
+
18
+ POST_HEADERS = {
19
+ "Accepts" => "application/xml",
20
+ "Content-Type" => "application/xml"
21
+ }
22
+
23
+ SUCCESS = "true"
24
+
25
+ SENSITIVE_FIELDS = [:verification_str2, :expiry_date, :card_number]
26
+
27
+ BRANDS = {
28
+ :visa => 'Visa',
29
+ :master => "Mastercard",
30
+ :american_express => "American Express",
31
+ :jcb => "JCB",
32
+ :discover => "Discover"
33
+ }
34
+
35
+ self.supported_cardtypes = BRANDS.keys
36
+ self.supported_countries = ["CA", "US"]
37
+ self.default_currency = "USD"
38
+ self.homepage_url = "http://www.firstdata.com"
39
+ self.display_name = "FirstData Global Gateway e4"
40
+
41
+ # Create a new FirstdataE4Gateway
42
+ #
43
+ # The gateway requires that a valid login and password be passed
44
+ # in the +options+ hash.
45
+ #
46
+ # ==== Options
47
+ #
48
+ # * <tt>:login</tt> -- The EXACT ID. Also known as the Gateway ID.
49
+ # (Found in your administration terminal settings)
50
+ # * <tt>:password</tt> -- The terminal password (not your account password)
51
+ def initialize(options = {})
52
+ requires!(options, :login, :password)
53
+ @options = options
54
+
55
+ super
56
+ end
57
+
58
+ def authorize(money, credit_card_or_store_authorization, options = {})
59
+ commit(:authorization, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options))
60
+ end
61
+
62
+ def purchase(money, credit_card_or_store_authorization, options = {})
63
+ commit(:sale, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options))
64
+ end
65
+
66
+ def capture(money, authorization, options = {})
67
+ commit(:capture, build_capture_or_credit_request(money, authorization, options))
68
+ end
69
+
70
+ def void(authorization, options = {})
71
+ commit(:void, build_capture_or_credit_request(money_from_authorization(authorization), authorization, options))
72
+ end
73
+
74
+ def refund(money, authorization, options = {})
75
+ commit(:credit, build_capture_or_credit_request(money, authorization, options))
76
+ end
77
+
78
+ def verify(credit_card, options = {})
79
+ commit(:verify, build_sale_or_authorization_request(0, credit_card, options))
80
+ end
81
+
82
+ # Tokenize a credit card with TransArmor
83
+ #
84
+ # The TransArmor token and other card data necessary for subsequent
85
+ # transactions is stored in the response's +authorization+ attribute.
86
+ # The authorization string may be passed to +authorize+ and +purchase+
87
+ # instead of a +ActiveMerchant::Billing::CreditCard+ instance.
88
+ #
89
+ # TransArmor support must be explicitly activated on your gateway
90
+ # account by FirstData. If your authorization string is empty, contact
91
+ # FirstData support for account setup assistance.
92
+ #
93
+ # === Example
94
+ #
95
+ # # Generate token
96
+ # result = gateway.store(credit_card)
97
+ # if result.success?
98
+ # my_record.update_attributes(:authorization => result.authorization)
99
+ # end
100
+ #
101
+ # # Use token
102
+ # result = gateway.purchase(1000, my_record.authorization)
103
+ #
104
+ # https://firstdata.zendesk.com/entries/21303361-transarmor-tokenization
105
+ def store(credit_card, options = {})
106
+ commit(:store, build_store_request(credit_card, options), credit_card)
107
+ end
108
+
109
+ private
110
+
111
+ def build_request(action, body)
112
+ xml = Builder::XmlMarkup.new
113
+
114
+ xml.instruct!
115
+ xml.tag! "Transaction" do
116
+ add_credentials(xml)
117
+ add_transaction_type(xml, action)
118
+ xml << body
119
+ end
120
+
121
+ xml.target!
122
+ end
123
+
124
+ def build_sale_or_authorization_request(money, credit_card_or_store_authorization, options)
125
+ xml = Builder::XmlMarkup.new
126
+
127
+ add_amount(xml, money)
128
+
129
+ if credit_card_or_store_authorization.is_a? String
130
+ add_credit_card_token(xml, credit_card_or_store_authorization)
131
+ else
132
+ add_credit_card(xml, credit_card_or_store_authorization, options)
133
+ end
134
+
135
+ add_customer_data(xml, options)
136
+ add_invoice(xml, options)
137
+ add_card_authentication_data(xml, options)
138
+
139
+ xml.target!
140
+ end
141
+
142
+ def build_capture_or_credit_request(money, identification, options)
143
+ xml = Builder::XmlMarkup.new
144
+
145
+ add_identification(xml, identification)
146
+ add_amount(xml, money)
147
+ add_customer_data(xml, options)
148
+ add_card_authentication_data(xml, options)
149
+
150
+ xml.target!
151
+ end
152
+
153
+ def build_store_request(credit_card, options)
154
+ xml = Builder::XmlMarkup.new
155
+
156
+ add_credit_card(xml, credit_card, options)
157
+ add_customer_data(xml, options)
158
+
159
+ xml.target!
160
+ end
161
+
162
+ def add_credentials(xml)
163
+ xml.tag! "ExactID", @options[:login]
164
+ xml.tag! "Password", @options[:password]
165
+ end
166
+
167
+ def add_transaction_type(xml, action)
168
+ xml.tag! "Transaction_Type", TRANSACTIONS[action]
169
+ end
170
+
171
+ def add_identification(xml, identification)
172
+ authorization_num, transaction_tag, _ = identification.split(";")
173
+
174
+ xml.tag! "Authorization_Num", authorization_num
175
+ xml.tag! "Transaction_Tag", transaction_tag
176
+ end
177
+
178
+ def add_amount(xml, money)
179
+ xml.tag! "DollarAmount", amount(money)
180
+ end
181
+
182
+ def add_credit_card(xml, credit_card, options)
183
+
184
+ if credit_card.respond_to?(:track_data) && credit_card.track_data.present?
185
+ xml.tag! "Track1", credit_card.track_data
186
+ else
187
+ xml.tag! "Card_Number", credit_card.number
188
+ xml.tag! "Expiry_Date", expdate(credit_card)
189
+ xml.tag! "CardHoldersName", credit_card.name
190
+ xml.tag! "CardType", card_type(credit_card.brand)
191
+
192
+ add_credit_card_verification_strings(xml, credit_card, options)
193
+ end
194
+ end
195
+
196
+ def add_credit_card_verification_strings(xml, credit_card, options)
197
+ address = options[:billing_address] || options[:address]
198
+ if address
199
+ address_values = []
200
+ [:address1, :zip, :city, :state, :country].each { |part| address_values << address[part].to_s }
201
+ xml.tag! "VerificationStr1", address_values.join("|")
202
+ end
203
+
204
+ if credit_card.verification_value?
205
+ xml.tag! "CVD_Presence_Ind", "1"
206
+ xml.tag! "VerificationStr2", credit_card.verification_value
207
+ end
208
+ end
209
+
210
+ def add_card_authentication_data(xml, options)
211
+ xml.tag! "CAVV", options[:cavv]
212
+ xml.tag! "XID", options[:xid]
213
+ xml.tag! "Ecommerce_Flag", options[:eci]
214
+ end
215
+
216
+ def add_credit_card_token(xml, store_authorization)
217
+ params = store_authorization.split(";")
218
+ credit_card = CreditCard.new(
219
+ :brand => params[1],
220
+ :first_name => params[2],
221
+ :last_name => params[3],
222
+ :month => params[4],
223
+ :year => params[5])
224
+
225
+ xml.tag! "TransarmorToken", params[0]
226
+ xml.tag! "Expiry_Date", expdate(credit_card)
227
+ xml.tag! "CardHoldersName", credit_card.name
228
+ xml.tag! "CardType", card_type(credit_card.brand)
229
+ end
230
+
231
+ def add_customer_data(xml, options)
232
+ xml.tag! "Customer_Ref", options[:customer] if options[:customer]
233
+ xml.tag! "Client_IP", options[:ip] if options[:ip]
234
+ xml.tag! "Client_Email", options[:email] if options[:email]
235
+ end
236
+
237
+ def add_address(xml, options)
238
+ if address = (options[:billing_address] || options[:address])
239
+ xml.tag! "ZipCode", address[:zip]
240
+ end
241
+ end
242
+
243
+ def add_invoice(xml, options)
244
+ xml.tag! "Reference_No", options[:order_id]
245
+ xml.tag! "Reference_3", options[:description] if options[:description]
246
+ end
247
+
248
+ def expdate(credit_card)
249
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
250
+ end
251
+
252
+ def card_type(credit_card_brand)
253
+ BRANDS[credit_card_brand.to_sym] if credit_card_brand
254
+ end
255
+
256
+ def commit(action, request, credit_card = nil)
257
+ url = (test? ? self.test_url : self.live_url)
258
+ begin
259
+ response = parse(ssl_post(url, build_request(action, request), POST_HEADERS))
260
+ rescue ResponseError => e
261
+ response = parse_error(e.response)
262
+ end
263
+
264
+ Response.new(successful?(response), message_from(response), response,
265
+ :test => test?,
266
+ :authorization => response_authorization(action, response, credit_card),
267
+ :avs_result => {:code => response[:avs]},
268
+ :cvv_result => response[:cvv2]
269
+ )
270
+ end
271
+
272
+ def successful?(response)
273
+ response[:transaction_approved] == SUCCESS
274
+ end
275
+
276
+ def response_authorization(action, response, credit_card)
277
+ if action == :store
278
+ store_authorization_from(response, credit_card)
279
+ else
280
+ authorization_from(response)
281
+ end
282
+ end
283
+
284
+ def authorization_from(response)
285
+ if response[:authorization_num] && response[:transaction_tag]
286
+ [
287
+ response[:authorization_num],
288
+ response[:transaction_tag],
289
+ (response[:dollar_amount].to_f * 100).to_i
290
+ ].join(";")
291
+ else
292
+ ""
293
+ end
294
+ end
295
+
296
+ def store_authorization_from(response, credit_card)
297
+ if response[:transarmor_token].present?
298
+ [
299
+ response[:transarmor_token],
300
+ credit_card.brand,
301
+ credit_card.first_name,
302
+ credit_card.last_name,
303
+ credit_card.month,
304
+ credit_card.year
305
+ ].map { |value| value.to_s.gsub(/;/, "") }.join(";")
306
+ else
307
+ raise StandardError, "TransArmor support is not enabled on your #{display_name} account"
308
+ end
309
+ end
310
+
311
+ def money_from_authorization(auth)
312
+ _, _, amount = auth.split(/;/, 3)
313
+ amount.to_i # return the # of cents, no need to divide
314
+ end
315
+
316
+ def message_from(response)
317
+ if(response[:faultcode] && response[:faultstring])
318
+ response[:faultstring]
319
+ elsif(response[:error_number] && response[:error_number] != "0")
320
+ response[:error_description]
321
+ else
322
+ result = (response[:exact_message] || "")
323
+ result << " - #{response[:bank_message]}" if response[:bank_message].present?
324
+ result
325
+ end
326
+ end
327
+
328
+ def parse_error(error)
329
+ {
330
+ :transaction_approved => "false",
331
+ :error_number => error.code,
332
+ :error_description => error.body
333
+ }
334
+ end
335
+
336
+ def parse(xml)
337
+ response = {}
338
+ xml = REXML::Document.new(xml)
339
+
340
+ if root = REXML::XPath.first(xml, "//TransactionResult")
341
+ parse_elements(response, root)
342
+ end
343
+
344
+ response.delete_if{ |k,v| SENSITIVE_FIELDS.include?(k) }
345
+ end
346
+
347
+ def parse_elements(response, root)
348
+ root.elements.to_a.each do |node|
349
+ response[node.name.gsub(/EXact/, "Exact").underscore.to_sym] = (node.text || "").strip
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end
355
+