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,448 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # iTransact, Inc. is an authorized reseller of the PaymentClearing gateway. If your merchant service provider uses PaymentClearing.com to process payments, you can use this module.
6
+ #
7
+ #
8
+ # Please note, the username and API Access Key are not what you use to log into the Merchant Control Panel.
9
+ #
10
+ # ==== How to get your GatewayID and API Access Key
11
+ #
12
+ # 1. If you don't already have a Gateway Account, go to http://www.itransact.com/merchant/test.html to sign up.
13
+ # 2. Go to http://support.paymentclearing.com and login or register, if necessary.
14
+ # 3. Click on "Submit a Ticket."
15
+ # 4. Select "Merchant Support" as the department and click "Next"
16
+ # 5. Enter *both* your company name and GatewayID. Put "API Access Key" in the subject. In the body, you can request a username, but it may already be in use.
17
+ #
18
+ # ==== Initialization
19
+ #
20
+ # Once you have the username, API Access Key, and your GatewayId, you're ready
21
+ # to begin. You initialize the Gateway like so:
22
+ #
23
+ # gateway = ActiveMerchant::Billing::ItransactGateway.new(
24
+ # :login => "#{THE_USERNAME}",
25
+ # :password => "#{THE_API_ACCESS_KEY}",
26
+ # :gateway_id => "#{THE_GATEWAY_ID}"
27
+ # )
28
+ #
29
+ # ==== Important Notes
30
+ # 1. Recurring is not implemented
31
+ # 1. CreditTransactions are not implemented (these are credits not related to a previously run transaction).
32
+ # 1. TransactionStatus is not implemented
33
+ #
34
+ class ItransactGateway < Gateway
35
+ self.live_url = self.test_url = 'https://secure.paymentclearing.com/cgi-bin/rc/xmltrans2.cgi'
36
+
37
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
38
+ self.supported_countries = ['US']
39
+
40
+ # The card types supported by the payment gateway
41
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
42
+
43
+ # The homepage URL of the gateway
44
+ self.homepage_url = 'http://www.itransact.com/'
45
+
46
+ # The name of the gateway
47
+ self.display_name = 'iTransact'
48
+
49
+ #
50
+ # Creates a new instance of the iTransact Gateway.
51
+ #
52
+ # ==== Parameters
53
+ # * <tt>options</tt> - A Hash of options
54
+ #
55
+ # ==== Options Hash
56
+ # * <tt>:login</tt> - A String containing your PaymentClearing assigned API Access Username
57
+ # * <tt>:password</tt> - A String containing your PaymentClearing assigned API Access Key
58
+ # * <tt>:gateway_id</tt> - A String containing your PaymentClearing assigned GatewayID
59
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Run *all* transactions with the 'TestMode' element set to 'TRUE'.
60
+ #
61
+ def initialize(options = {})
62
+ requires!(options, :login, :password, :gateway_id)
63
+ super
64
+ end
65
+
66
+ # Performs an authorize transaction. In PaymentClearing's documentation
67
+ # this is known as a "PreAuth" transaction.
68
+ #
69
+ # ==== Parameters
70
+ # * <tt>money</tt> - The amount to be captured. Should be an Integer amount in cents.
71
+ # * <tt>creditcard</tt> - The CreditCard details for the transaction
72
+ # * <tt>options</tt> - A Hash of options
73
+ #
74
+ # ==== Options Hash
75
+ # The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
76
+ # * <tt>:order_items</tt> - An Array of Hash objects with the keys <tt>:description</tt>, <tt>:cost</tt> (in cents!), and <tt>:quantity</tt>. If this is provided, <tt>:description</tt> and <tt>money</tt> will be ignored.
77
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
78
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
79
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
80
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
81
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
82
+ #
83
+ # ==== Examples
84
+ # response = gateway.authorize(1000, creditcard,
85
+ # :order_id => '1212', :address => {...}, :email => 'test@test.com',
86
+ # :order_items => [
87
+ # {:description => 'Line Item 1', :cost => '8.98', :quantity => '6'},
88
+ # {:description => 'Line Item 2', :cost => '6.99', :quantity => '4'}
89
+ # ],
90
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
91
+ # :send_customer_email => true,
92
+ # :send_merchant_email => true,
93
+ # :email_text => ['line1', 'line2', 'line3'],
94
+ # :test_mode => true
95
+ # )
96
+ #
97
+ def authorize(money, payment_source, options = {})
98
+ payload = Nokogiri::XML::Builder.new do |xml|
99
+ xml.AuthTransaction {
100
+ xml.Preauth
101
+ add_customer_data(xml, payment_source, options)
102
+ add_invoice(xml, money, options)
103
+ add_payment_source(xml, payment_source)
104
+ add_transaction_control(xml, options)
105
+ add_vendor_data(xml, options)
106
+ }
107
+ end.doc
108
+
109
+ commit(payload)
110
+ end
111
+
112
+ # Performs an authorize and capture in single transaction. In PaymentClearing's
113
+ # documentation this is known as an "Auth" or a "Sale" transaction
114
+ #
115
+ # ==== Parameters
116
+ # * <tt>money</tt> - The amount to be captured. Should be <tt>nil</tt> or an Integer amount in cents.
117
+ # * <tt>creditcard</tt> - The CreditCard details for the transaction
118
+ # * <tt>options</tt> - A Hash of options
119
+ #
120
+ # ==== Options Hash
121
+ # The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
122
+ # * <tt>:order_items</tt> - An Array of Hash objects with the keys <tt>:description</tt>, <tt>:cost</tt> (in cents!), and <tt>:quantity</tt>. If this is provided, <tt>:description</tt> and <tt>money</tt> will be ignored.
123
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
124
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
125
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
126
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
127
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
128
+ #
129
+ # ==== Examples
130
+ # response = gateway.purchase(1000, creditcard,
131
+ # :order_id => '1212', :address => {...}, :email => 'test@test.com',
132
+ # :order_items => [
133
+ # {:description => 'Line Item 1', :cost => '8.98', :quantity => '6'},
134
+ # {:description => 'Line Item 2', :cost => '6.99', :quantity => '4'}
135
+ # ],
136
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
137
+ # :send_customer_email => true,
138
+ # :send_merchant_email => true,
139
+ # :email_text => ['line1', 'line2', 'line3'],
140
+ # :test_mode => true
141
+ # )
142
+ #
143
+ def purchase(money, payment_source, options = {})
144
+ payload = Nokogiri::XML::Builder.new do |xml|
145
+ xml.AuthTransaction {
146
+ add_customer_data(xml, payment_source, options)
147
+ add_invoice(xml, money, options)
148
+ add_payment_source(xml, payment_source)
149
+ add_transaction_control(xml, options)
150
+ add_vendor_data(xml, options)
151
+ }
152
+ end.doc
153
+
154
+ commit(payload)
155
+ end
156
+
157
+ # Captures the funds from an authorize transaction. In PaymentClearing's
158
+ # documentation this is known as a "PostAuth" transaction.
159
+ #
160
+ # ==== Parameters
161
+ # * <tt>money</tt> - The amount to be captured. Should be an Integer amount in cents
162
+ # * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
163
+ # * <tt>options</tt> - A Hash of options, all are optional.
164
+ #
165
+ # ==== Options Hash
166
+ # The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
167
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
168
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
169
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
170
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
171
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
172
+ #
173
+ # ==== Examples
174
+ # response = gateway.capture(1000, creditcard,
175
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
176
+ # :send_customer_email => true,
177
+ # :send_merchant_email => true,
178
+ # :email_text => ['line1', 'line2', 'line3'],
179
+ # :test_mode => true
180
+ # )
181
+ #
182
+ def capture(money, authorization, options = {})
183
+ payload = Nokogiri::XML::Builder.new do |xml|
184
+ xml.PostAuthTransaction {
185
+ xml.OperationXID(authorization)
186
+ add_invoice(xml, money, options)
187
+ add_transaction_control(xml, options)
188
+ add_vendor_data(xml, options)
189
+ }
190
+ end.doc
191
+
192
+ commit(payload)
193
+ end
194
+
195
+ # This will reverse a previously run transaction which *has* *not* settled.
196
+ #
197
+ # ==== Parameters
198
+ # * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
199
+ # * <tt>options</tt> - A Hash of options, all are optional
200
+ #
201
+ # ==== Options Hash
202
+ # The standard options (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address) are ignored.
203
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
204
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
205
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
206
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
207
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
208
+ #
209
+ # ==== Examples
210
+ # response = gateway.void('9999999999',
211
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
212
+ # :send_customer_email => true,
213
+ # :send_merchant_email => true,
214
+ # :email_text => ['line1', 'line2', 'line3'],
215
+ # :test_mode => true
216
+ # )
217
+ #
218
+ def void(authorization, options = {})
219
+ payload = Nokogiri::XML::Builder.new do |xml|
220
+ xml.VoidTransaction {
221
+ xml.OperationXID(authorization)
222
+ add_transaction_control(xml, options)
223
+ add_vendor_data(xml, options)
224
+ }
225
+ end.doc
226
+
227
+ commit(payload)
228
+ end
229
+
230
+ # This will reverse a previously run transaction which *has* settled.
231
+ #
232
+ # ==== Parameters
233
+ # * <tt>money</tt> - The amount to be credited. Should be an Integer amount in cents
234
+ # * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
235
+ # * <tt>options</tt> - A Hash of options, all are optional
236
+ #
237
+ # ==== Options Hash
238
+ # The standard options (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address) are ignored.
239
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
240
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
241
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
242
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
243
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
244
+ #
245
+ # ==== Examples
246
+ # response = gateway.refund(555, '9999999999',
247
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
248
+ # :send_customer_email => true,
249
+ # :send_merchant_email => true,
250
+ # :email_text => ['line1', 'line2', 'line3'],
251
+ # :test_mode => true
252
+ # )
253
+ #
254
+ def refund(money, authorization, options = {})
255
+ payload = Nokogiri::XML::Builder.new do |xml|
256
+ xml.TranCredTransaction {
257
+ xml.OperationXID(authorization)
258
+ add_invoice(xml, money, options)
259
+ add_transaction_control(xml, options)
260
+ add_vendor_data(xml, options)
261
+ }
262
+ end.doc
263
+
264
+ commit(payload)
265
+ end
266
+
267
+ private
268
+
269
+ def add_customer_data(xml, payment_source, options)
270
+ billing_address = options[:billing_address] || options[:address]
271
+ shipping_address = options[:shipping_address] || options[:address]
272
+
273
+ xml.CustomerData {
274
+ xml.Email(options[:email]) unless options[:email].blank?
275
+ xml.CustId(options[:order_id]) unless options[:order_id].blank?
276
+ xml.BillingAddress {
277
+ xml.FirstName(payment_source.first_name || parse_first_name(billing_address[:name]))
278
+ xml.LastName(payment_source.last_name || parse_last_name(billing_address[:name]))
279
+ xml.Address1(billing_address[:address1])
280
+ xml.Address2(billing_address[:address2]) unless billing_address[:address2].blank?
281
+ xml.City(billing_address[:city])
282
+ xml.State(billing_address[:state])
283
+ xml.Zip(billing_address[:zip])
284
+ xml.Country(billing_address[:country])
285
+ xml.Phone(billing_address[:phone])
286
+ }
287
+ xml.ShippingAddress {
288
+ xml.FirstName(payment_source.first_name || parse_first_name(shipping_address[:name]))
289
+ xml.LastName(payment_source.last_name || parse_last_name(shipping_address[:name]))
290
+ xml.Address1(shipping_address[:address1])
291
+ xml.Address2(shipping_address[:address2]) unless shipping_address[:address2].blank?
292
+ xml.City(shipping_address[:city])
293
+ xml.State(shipping_address[:state])
294
+ xml.Zip(shipping_address[:zip])
295
+ xml.Country(shipping_address[:country])
296
+ xml.Phone(shipping_address[:phone])
297
+ } unless shipping_address.blank?
298
+ }
299
+ end
300
+
301
+ def add_invoice(xml, money, options)
302
+ xml.AuthCode options[:force] if options[:force]
303
+ if options[:order_items].blank?
304
+ xml.Total(amount(money)) unless(money.nil? || money < 0.01)
305
+ xml.Description(options[:description]) unless( options[:description].blank?)
306
+ else
307
+ xml.OrderItems {
308
+ options[:order_items].each do |item|
309
+ xml.Item {
310
+ xml.Description(item[:description])
311
+ xml.Cost(amount(item[:cost]))
312
+ xml.Qty(item[:quantity].to_s)
313
+ }
314
+ end
315
+ }
316
+ end
317
+ end
318
+
319
+ def add_payment_source(xml, source)
320
+ case determine_funding_source(source)
321
+ when :credit_card then add_creditcard(xml, source)
322
+ when :check then add_check(xml, source)
323
+ end
324
+ end
325
+
326
+ def determine_funding_source(payment_source)
327
+ case payment_source
328
+ when ActiveMerchant::Billing::CreditCard
329
+ :credit_card
330
+ when ActiveMerchant::Billing::Check
331
+ :check
332
+ end
333
+ end
334
+
335
+ def add_creditcard(xml, creditcard)
336
+ xml.AccountInfo {
337
+ xml.CardAccount {
338
+ xml.AccountNumber(creditcard.number.to_s)
339
+ xml.ExpirationMonth(creditcard.month.to_s.rjust(2,'0'))
340
+ xml.ExpirationYear(creditcard.year.to_s)
341
+ xml.CVVNumber(creditcard.verification_value.to_s) unless creditcard.verification_value.blank?
342
+ }
343
+ }
344
+ end
345
+
346
+ def add_check(xml, check)
347
+ xml.AccountInfo {
348
+ xml.ABA(check.routing_number.to_s)
349
+ xml.AccountNumber(check.account_number.to_s)
350
+ xml.AccountSource(check.account_type.to_s)
351
+ xml.AccountType(check.account_holder_type.to_s)
352
+ xml.CheckNumber(check.number.to_s)
353
+ }
354
+ end
355
+
356
+ def add_transaction_control(xml, options)
357
+ xml.TransactionControl {
358
+ # if there was a 'global' option set...
359
+ xml.TestMode(@options[:test_mode].upcase) if !@options[:test_mode].blank?
360
+ # allow the global option to be overridden...
361
+ xml.TestMode(options[:test_mode].upcase) if !options[:test_mode].blank?
362
+ xml.SendCustomerEmail(options[:send_customer_email].upcase) unless options[:send_customer_email].blank?
363
+ xml.SendMerchantEmail(options[:send_merchant_email].upcase) unless options[:send_merchant_email].blank?
364
+ xml.EmailText {
365
+ options[:email_text].each do |item|
366
+ xml.EmailTextItem(item)
367
+ end
368
+ } if options[:email_text]
369
+ }
370
+ end
371
+
372
+ def add_vendor_data(xml, options)
373
+ return if options[:vendor_data].blank?
374
+ xml.VendorData {
375
+ options[:vendor_data].each do |k,v|
376
+ xml.Element {
377
+ xml.Name(k)
378
+ xml.Key(v)
379
+ }
380
+ end
381
+ }
382
+ end
383
+
384
+ def commit(payload)
385
+ # Set the Content-Type header -- otherwise the URL decoding messes up
386
+ # the Base64 encoded payload signature!
387
+ response = parse(ssl_post(self.live_url, post_data(payload), 'Content-Type' => 'text/xml'))
388
+
389
+ Response.new(successful?(response), response[:error_message], response,
390
+ :test => test?,
391
+ :authorization => response[:xid],
392
+ :avs_result => { :code => response[:avs_response] },
393
+ :cvv_result => response[:cvv_response])
394
+ end
395
+
396
+ def post_data(payload)
397
+ payload_xml = payload.root.to_xml(:indent => 0)
398
+
399
+ payload_signature = sign_payload(payload_xml)
400
+
401
+ request = Nokogiri::XML::Builder.new do |xml|
402
+ xml.GatewayInterface {
403
+ xml.APICredentials {
404
+ xml.Username(@options[:login])
405
+ xml.PayloadSignature(payload_signature)
406
+ xml.TargetGateway(@options[:gateway_id])
407
+ }
408
+ }
409
+ end.doc
410
+
411
+ request.root.children.first.after payload.root
412
+ request.to_xml(:indent => 0)
413
+ end
414
+
415
+ def parse(raw_xml)
416
+ doc = REXML::Document.new(raw_xml)
417
+ response = Hash.new
418
+ transaction_result = doc.root.get_elements('TransactionResponse/TransactionResult/*')
419
+ transaction_result.each do |e|
420
+ response[e.name.to_s.underscore.to_sym] = e.text unless e.text.blank?
421
+ end
422
+ response
423
+ end
424
+
425
+ def successful?(response)
426
+ # Turns out the PaymentClearing gateway is not consistent...
427
+ response[:status].downcase =='ok'
428
+ end
429
+
430
+ def test_mode?(response)
431
+ # The '1' is a legacy thing; most of the time it should be 'TRUE'...
432
+ response[:test_mode] == 'TRUE' || response[:test_mode] == '1'
433
+ end
434
+
435
+ def message_from(response)
436
+ response[:error_message]
437
+ end
438
+
439
+ def sign_payload(payload)
440
+ key = @options[:password].to_s
441
+ digest=OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new(key), key, payload)
442
+ signature = Base64.encode64(digest)
443
+ signature.chomp!
444
+ end
445
+ end
446
+ end
447
+ end
448
+
@@ -0,0 +1,275 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class JetpayGateway < Gateway
4
+ self.test_url = 'https://test1.jetpay.com/jetpay'
5
+ self.live_url = 'https://gateway17.jetpay.com/jetpay'
6
+
7
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
8
+ self.supported_countries = ['US']
9
+
10
+ # The card types supported by the payment gateway
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
+
13
+ # The homepage URL of the gateway
14
+ self.homepage_url = 'http://www.jetpay.com/'
15
+
16
+ # The name of the gateway
17
+ self.display_name = 'JetPay'
18
+
19
+ # all transactions are in cents
20
+ self.money_format = :cents
21
+
22
+ ACTION_CODE_MESSAGES = {
23
+ "001" => "Refer to card issuer.",
24
+ "002" => "Refer to card issuer, special condition.",
25
+ "003" => "Pick up card.",
26
+ "200" => "Deny - Pick up card.",
27
+ "005" => "Do not honor.",
28
+ "100" => "Deny.",
29
+ "006" => "Error.",
30
+ "181" => "Format error.",
31
+ "007" => "Pickup card, special condition.",
32
+ "104" => "Deny - New card issued.",
33
+ "110" => "Invalid amount.",
34
+ "014" => "Invalid account number (no such number).",
35
+ "111" => "Invalid account.",
36
+ "015" => "No such issuer.",
37
+ "103" => "Deny - Invalid manual Entry 4DBC.",
38
+ "182" => "Please wait.",
39
+ "109" => "Invalid merchant.",
40
+ "041" => "Pick up card (lost card).",
41
+ "043" => "Pick up card (stolen card).",
42
+ "051" => "Insufficient funds.",
43
+ "052" => "No checking account.",
44
+ "105" => "Deny - Account Cancelled.",
45
+ "054" => "Expired Card.",
46
+ "101" => "Expired Card.",
47
+ "183" => "Invalid currency code.",
48
+ "057" => "Transaction not permitted to cardholder.",
49
+ "115" => "Service not permitted.",
50
+ "062" => "Restricted card.",
51
+ "189" => "Deny - Cancelled or Closed Merchant/SE.",
52
+ "188" => "Deny - Expiration date required.",
53
+ "125" => "Invalid effective date.",
54
+ "122" => "Invalid card (CID) security code.",
55
+ "400" => "Reversal accepted.",
56
+ "992" => "DECLINE/TIMEOUT.",
57
+ "107" => "Please Call Issuer.",
58
+ "025" => "Transaction Not Found.",
59
+ "981" => "AVS Error.",
60
+ "913" => "Invalid Card Type.",
61
+ "996" => "Terminal ID Not Found.",
62
+ nil => "No response returned (missing credentials?)."
63
+ }
64
+
65
+ def initialize(options = {})
66
+ requires!(options, :login)
67
+ super
68
+ end
69
+
70
+ def purchase(money, credit_card, options = {})
71
+ commit(money, build_sale_request(money, credit_card, options))
72
+ end
73
+
74
+ def authorize(money, credit_card, options = {})
75
+ commit(money, build_authonly_request(money, credit_card, options))
76
+ end
77
+
78
+ def capture(money, reference, options = {})
79
+ commit(money, build_capture_request('CAPT', reference.split(";").first))
80
+ end
81
+
82
+ def void(reference, options = {})
83
+ transaction_id, approval, amount = reference.split(";")
84
+ commit(amount.to_i, build_void_request(amount.to_i, transaction_id, approval))
85
+ end
86
+
87
+ def credit(money, transaction_id_or_card, options = {})
88
+ if transaction_id_or_card.is_a?(String)
89
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
90
+ refund(money, transaction_id_or_card, options)
91
+ else
92
+ commit(money, build_credit_request('CREDIT', money, nil, transaction_id_or_card))
93
+ end
94
+ end
95
+
96
+ def refund(money, reference, options = {})
97
+ transaction_id = reference.split(";").first
98
+ credit_card = options[:credit_card]
99
+ commit(money, build_credit_request('CREDIT', money, transaction_id, credit_card))
100
+ end
101
+
102
+
103
+ private
104
+
105
+ def build_xml_request(transaction_type, transaction_id = nil, &block)
106
+ xml = Builder::XmlMarkup.new
107
+ xml.tag! 'JetPay' do
108
+ # The basic values needed for any request
109
+ xml.tag! 'TerminalID', @options[:login]
110
+ xml.tag! 'TransactionType', transaction_type
111
+ xml.tag! 'TransactionID', transaction_id.nil? ? generate_unique_id.slice(0, 18) : transaction_id
112
+
113
+ if block_given?
114
+ yield xml
115
+ else
116
+ xml.target!
117
+ end
118
+ end
119
+ end
120
+
121
+ def build_sale_request(money, credit_card, options)
122
+ build_xml_request('SALE') do |xml|
123
+ add_credit_card(xml, credit_card)
124
+ add_addresses(xml, options)
125
+ add_customer_data(xml, options)
126
+ add_invoice_data(xml, options)
127
+ xml.tag! 'TotalAmount', amount(money)
128
+
129
+ xml.target!
130
+ end
131
+ end
132
+
133
+ def build_authonly_request(money, credit_card, options)
134
+ build_xml_request('AUTHONLY') do |xml|
135
+ add_credit_card(xml, credit_card)
136
+ add_addresses(xml, options)
137
+ add_customer_data(xml, options)
138
+ add_invoice_data(xml, options)
139
+ xml.tag! 'TotalAmount', amount(money)
140
+
141
+ xml.target!
142
+ end
143
+ end
144
+
145
+ def build_capture_request(transaction_type, transaction_id)
146
+ build_xml_request(transaction_type, transaction_id)
147
+ end
148
+
149
+ def build_void_request(money, transaction_id, approval)
150
+ build_xml_request('VOID', transaction_id) do |xml|
151
+ xml.tag! 'Approval', approval
152
+ xml.tag! 'TotalAmount', amount(money)
153
+
154
+ xml.target!
155
+ end
156
+ end
157
+
158
+ # `transaction_id` may be nil for unlinked credit transactions.
159
+ def build_credit_request(transaction_type, money, transaction_id, card)
160
+ build_xml_request(transaction_type, transaction_id) do |xml|
161
+ add_credit_card(xml, card) if card
162
+ xml.tag! 'TotalAmount', amount(money)
163
+
164
+ xml.target!
165
+ end
166
+ end
167
+
168
+ def commit(money, request)
169
+ response = parse(ssl_post(test? ? self.test_url : self.live_url, request))
170
+
171
+ success = success?(response)
172
+ Response.new(success,
173
+ success ? 'APPROVED' : message_from(response),
174
+ response,
175
+ :test => test?,
176
+ :authorization => authorization_from(response, money),
177
+ :avs_result => { :code => response[:avs] },
178
+ :cvv_result => response[:cvv2]
179
+ )
180
+ end
181
+
182
+ def parse(body)
183
+ return {} if body.blank?
184
+
185
+ xml = REXML::Document.new(body)
186
+
187
+ response = {}
188
+ xml.root.elements.to_a.each do |node|
189
+ parse_element(response, node)
190
+ end
191
+ response
192
+ end
193
+
194
+ def parse_element(response, node)
195
+ if node.has_elements?
196
+ node.elements.each{|element| parse_element(response, element) }
197
+ else
198
+ response[node.name.underscore.to_sym] = node.text
199
+ end
200
+ end
201
+
202
+ def format_exp(value)
203
+ format(value, :two_digits)
204
+ end
205
+
206
+ def success?(response)
207
+ response[:action_code] == "000"
208
+ end
209
+
210
+ def message_from(response)
211
+ ACTION_CODE_MESSAGES[response[:action_code]]
212
+ end
213
+
214
+ def authorization_from(response, money)
215
+ original_amount = amount(money) if money
216
+ [ response[:transaction_id], response[:approval], original_amount ].join(";")
217
+ end
218
+
219
+ def add_credit_card(xml, credit_card)
220
+ xml.tag! 'CardNum', credit_card.number
221
+ xml.tag! 'CardExpMonth', format_exp(credit_card.month)
222
+ xml.tag! 'CardExpYear', format_exp(credit_card.year)
223
+
224
+ if credit_card.first_name || credit_card.last_name
225
+ xml.tag! 'CardName', [credit_card.first_name,credit_card.last_name].compact.join(' ')
226
+ end
227
+
228
+ unless credit_card.verification_value.nil? || (credit_card.verification_value.length == 0)
229
+ xml.tag! 'CVV2', credit_card.verification_value
230
+ end
231
+ end
232
+
233
+ def add_addresses(xml, options)
234
+ if billing_address = options[:billing_address] || options[:address]
235
+ xml.tag! 'BillingAddress', [billing_address[:address1], billing_address[:address2]].compact.join(" ")
236
+ xml.tag! 'BillingCity', billing_address[:city]
237
+ xml.tag! 'BillingStateProv', billing_address[:state]
238
+ xml.tag! 'BillingPostalCode', billing_address[:zip]
239
+ xml.tag! 'BillingCountry', lookup_country_code(billing_address[:country])
240
+ xml.tag! 'BillingPhone', billing_address[:phone]
241
+ end
242
+
243
+ if shipping_address = options[:shipping_address]
244
+ xml.tag! 'ShippingInfo' do
245
+ xml.tag! 'ShippingName', shipping_address[:name]
246
+
247
+ xml.tag! 'ShippingAddr' do
248
+ xml.tag! 'Address', [shipping_address[:address1], shipping_address[:address2]].compact.join(" ")
249
+ xml.tag! 'City', shipping_address[:city]
250
+ xml.tag! 'StateProv', shipping_address[:state]
251
+ xml.tag! 'PostalCode', shipping_address[:zip]
252
+ xml.tag! 'Country', lookup_country_code(shipping_address[:country])
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ def add_customer_data(xml, options)
259
+ xml.tag! 'Email', options[:email] if options[:email]
260
+ xml.tag! 'UserIPAddress', options[:ip] if options[:ip]
261
+ end
262
+
263
+ def add_invoice_data(xml, options)
264
+ xml.tag! 'OrderNumber', options[:order_id] if options[:order_id]
265
+ xml.tag! 'TaxAmount', amount(options[:tax]) if options[:tax]
266
+ end
267
+
268
+ def lookup_country_code(code)
269
+ country = Country.find(code) rescue nil
270
+ country && country.code(:alpha3)
271
+ end
272
+ end
273
+ end
274
+ end
275
+