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,25 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ ##
4
+ # Delegates to the appropriate gateway, either the Transaction or Advanced
5
+ # depending on options passed to new.
6
+ #
7
+ class UsaEpayGateway < Gateway
8
+
9
+ self.abstract_class = true
10
+
11
+ ##
12
+ # Creates an instance of UsaEpayTransactionGateway by default, but if
13
+ # :software id or :live_url are passed in the options hash it will
14
+ # create an instance of UsaEpayAdvancedGateway.
15
+ #
16
+ def self.new(options={})
17
+ unless options.has_key?(:software_id) || options.has_key?(:live_url)
18
+ UsaEpayTransactionGateway.new(options)
19
+ else
20
+ UsaEpayAdvancedGateway.new(options)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,1516 @@
1
+ require 'securerandom'
2
+ require 'digest'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ # ==== USA ePay Advanced SOAP Interface
7
+ #
8
+ # This class encapuslates USA ePay's Advanced SOAP Interface. The Advanced Soap Interface allows
9
+ # standard transactions, storing customer information, and recurring billing. Storing sensitive
10
+ # information on USA ePay's servers can help with PCI DSS compliance, since customer and card data
11
+ # do not need to be stored locally.
12
+ #
13
+ # Make sure you have enabled this functionality for your account with USA ePay.
14
+ #
15
+ # Information about the Advanced SOAP interface is available on the {USA ePay wiki}[http://wiki.usaepay.com/developer/soap].
16
+ #
17
+ # ==== Login, Password, and Software ID
18
+ #
19
+ # Please follow all of USA ePay's directions for acquiring all accounts and settings.
20
+ #
21
+ # The value used for <tt>:login</tt> is the Key value found in the Merchant Console under Settings > Source
22
+ # Key. You will have to add this key in the USA ePay Merchant Console.
23
+ #
24
+ # The value used for <tt>:password</tt> is the pin value also found and assigned in the Merchant Console under
25
+ # Settings > Source Key. The pin is required to use all but basic transactions in the SOAP interface.
26
+ # You will have to add the pin to your source key, as it defaults to none.
27
+ #
28
+ # The value used for the <tt>:software_id</tt> is found in the Developer's Login under the Developers Center
29
+ # in your WSDL. It is the 8 character value in <soap:address> tag. A masked example:
30
+ # <soap:address location="https://www.usaepay.com/soap/gate/XXXXXXXX"/>
31
+ # It is also found in the link to your WSDL. This is required as every account has a different path
32
+ # SOAP requests are submitted to. Optionally, you can provide the entire urls via <tt>:live_url</tt> and <tt>:test_url</tt>, if your prefer.
33
+ #
34
+ # ==== Responses
35
+ # * <tt>#success?</tt> -- +true+ if transmitted and returned correctly
36
+ # * <tt>#message</tt> -- response or fault message
37
+ # * <tt>#authorization</tt> -- reference_number or nil
38
+ # * <tt>#params</tt> -- hash of entire soap response contents
39
+ #
40
+ # ==== Address Options
41
+ # * <tt>:billing_address/:shipping_address</tt> -- contains some extra options
42
+ # * <tt>:name</tt> -- virtual attribute; will split to first and last name
43
+ # * <tt>:first_name</tt>
44
+ # * <tt>:last_name</tt>
45
+ # * <tt>:address1 </tt>
46
+ # * <tt>:address2 </tt>
47
+ # * <tt>:city </tt>
48
+ # * <tt>:state </tt>
49
+ # * <tt>:zip </tt>
50
+ # * <tt>:country </tt>
51
+ # * <tt>:phone</tt>
52
+ # * <tt>:email</tt>
53
+ # * <tt>:fax</tt>
54
+ # * <tt>:company</tt>
55
+ #
56
+ # ==== Support:
57
+ # * Questions: post to {active_merchant google group}[http://groups.google.com/group/activemerchant]
58
+ # * Feedback/fixes: matt (at) nearapogee (dot) com
59
+ #
60
+ # ==== Links:
61
+ # * {USA ePay Merchant Console}[https://sandbox.usaepay.com/login]
62
+ # * {USA ePay Developer Login}[https://www.usaepay.com/developer/login]
63
+ #
64
+ class UsaEpayAdvancedGateway < Gateway
65
+ API_VERSION = "1.4"
66
+
67
+ TEST_URL_BASE = 'https://sandbox.usaepay.com/soap/gate/' #:nodoc:
68
+ LIVE_URL_BASE = 'https://www.usaepay.com/soap/gate/' #:nodoc:
69
+
70
+ self.test_url = TEST_URL_BASE
71
+ self.live_url = LIVE_URL_BASE
72
+
73
+ FAILURE_MESSAGE = "Default Failure" #:nodoc:
74
+
75
+ self.supported_countries = ['US']
76
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
77
+ self.homepage_url = 'http://www.usaepay.com/'
78
+ self.display_name = 'USA ePay Advanced SOAP Interface'
79
+
80
+ CUSTOMER_OPTIONS = {
81
+ :id => [:string, 'CustomerID'], # merchant assigned number
82
+ :notes => [:string, 'Notes'],
83
+ :data => [:string, 'CustomData'],
84
+ :url => [:string, 'URL'],
85
+ # Recurring Billing
86
+ :enabled => [:boolean, 'Enabled'],
87
+ :schedule => [:string, 'Schedule'],
88
+ :number_left => [:integer, 'NumLeft'],
89
+ :currency => [:string, 'Currency'],
90
+ :description => [:string, 'Description'],
91
+ :order_id => [:string, 'OrderID'],
92
+ :user => [:string, 'User'],
93
+ :source => [:string, 'Source'],
94
+ :send_receipt => [:boolean, 'SendReceipt'],
95
+ :receipt_note => [:string, 'ReceiptNote'],
96
+ # Point of Sale
97
+ :price_tier => [:string, 'PriceTier'],
98
+ :tax_class => [:string, 'TaxClass'],
99
+ :lookup_code => [:string, 'LookupCode']
100
+ } #:nodoc:
101
+
102
+ ADDRESS_OPTIONS = {
103
+ :first_name => [:string, 'FirstName'],
104
+ :last_name => [:string, 'LastName'],
105
+ :address1 => [:string, 'Street'],
106
+ :address2 => [:string, 'Street2'],
107
+ :city => [:string, 'City'],
108
+ :state => [:string, 'State'],
109
+ :zip => [:string, 'Zip'],
110
+ :country => [:string, 'Country'],
111
+ :phone => [:string, 'Phone'],
112
+ :email => [:string, 'Email'],
113
+ :fax => [:string, 'Fax'],
114
+ :company => [:string, 'Company']
115
+ } #:nodoc:
116
+
117
+ CUSTOMER_TRANSACTION_REQUEST_OPTIONS = {
118
+ :command => [:string, 'Command'],
119
+ :ignore_duplicate => [:boolean, 'IgnoreDuplicate'],
120
+ :client_ip => [:string, 'ClientIP'],
121
+ :customer_receipt => [:boolean, 'CustReceipt'],
122
+ :customer_email => [:boolean, 'CustReceiptEmail'],
123
+ :customer_template => [:boolean, 'CustReceiptName'],
124
+ :merchant_receipt => [:boolean, 'MerchReceipt'],
125
+ :merchant_email => [:boolean, 'MerchReceiptEmail'],
126
+ :merchant_template => [:boolean, 'MerchReceiptName'],
127
+ :recurring => [:boolean, 'isRecurring'],
128
+ :verification_value => [:string, 'CardCode'],
129
+ :software => [:string, 'Software']
130
+ } #:nodoc:
131
+
132
+ TRANSACTION_REQUEST_OBJECT_OPTIONS = {
133
+ :command => [:string, 'Command'],
134
+ :ignore_duplicate => [:boolean, 'IgnoreDuplicate'],
135
+ :authorization_code => [:string, 'AuthCode'],
136
+ :reference_number => [:string, 'RefNum'],
137
+ :account_holder => [:string, 'AccountHolder'],
138
+ :client_ip => [:string, 'ClientIP'],
139
+ :customer_id => [:string, 'CustomerID'],
140
+ :customer_receipt => [:boolean, 'CustReceipt'],
141
+ :customer_template => [:boolean, 'CustReceiptName'],
142
+ :software => [:string, 'Software']
143
+ } #:nodoc:
144
+
145
+ TRANSACTION_DETAIL_OPTIONS = {
146
+ :invoice => [:string, 'Invoice'],
147
+ :po_number => [:string, 'PONum'],
148
+ :order_id => [:string, 'OrderID'],
149
+ :clerk => [:string, 'Clerk'],
150
+ :terminal => [:string, 'Terminal'],
151
+ :table => [:string, 'Table'],
152
+ :description => [:string, 'Description'],
153
+ :comments => [:string, 'Comments'],
154
+ :allow_partial_auth => [:boolean, 'AllowPartialAuth'],
155
+ :currency => [:string, 'Currency'],
156
+ :non_tax => [:boolean, 'NonTax'],
157
+ } #:nodoc:
158
+
159
+ TRANSACTION_DETAIL_MONEY_OPTIONS = {
160
+ :amount => [:double, 'Amount'],
161
+ :tax => [:double, 'Tax'],
162
+ :tip => [:double, 'Tip'],
163
+ :non_tax => [:boolean, 'NonTax'],
164
+ :shipping => [:double, 'Shipping'],
165
+ :discount => [:double, 'Discount'],
166
+ :subtotal => [:double, 'Subtotal']
167
+ } #:nodoc:
168
+
169
+ CREDIT_CARD_DATA_OPTIONS = {
170
+ :magnetic_stripe => [:string, 'MagStripe'],
171
+ :dukpt => [:string, 'DUKPT'],
172
+ :signature => [:string, 'Signature'],
173
+ :terminal_type => [:string, 'TermType'],
174
+ :magnetic_support => [:string, 'MagSupport'],
175
+ :xid => [:string, 'XID'],
176
+ :cavv => [:string, 'CAVV'],
177
+ :eci => [:integer, 'ECI'],
178
+ :internal_card_authorization => [:boolean, 'InternalCardAuth'],
179
+ :pares => [:string, 'Pares']
180
+ } #:nodoc:
181
+
182
+ CHECK_DATA_OPTIONS = {
183
+ :drivers_license => [:string, 'DriversLicense'],
184
+ :drivers_license_state => [:string, 'DriversLicenseState'],
185
+ :record_type => [:string, 'RecordType'],
186
+ :aux_on_us => [:string, 'AuxOnUS'],
187
+ :epc_code => [:string, 'EpcCode'],
188
+ :front_image => [:string, 'FrontImage'],
189
+ :back_image => [:string, 'BackImage']
190
+ } #:nodoc:
191
+
192
+ RECURRING_BILLING_OPTIONS = {
193
+ :schedule => [:string, 'Schedule'],
194
+ :number_left => [:integer, 'NumLeft'],
195
+ :enabled => [:boolean, 'Enabled']
196
+ } #:nodoc:
197
+
198
+ AVS_RESULTS = {
199
+ 'Y' => %w( YYY Y YYA YYD ),
200
+ 'Z' => %w( NYZ Z ),
201
+ 'A' => %w( YNA A YNY ),
202
+ 'N' => %w( NNN N NN ),
203
+ 'X' => %w( YYX X ),
204
+ 'W' => %w( NYW W ),
205
+ 'XXW' => %w( XXW ),
206
+ 'XXU' => %w( XXU ),
207
+ 'R' => %w( XXR R U E ),
208
+ 'S' => %w( XXS S ),
209
+ 'XXE' => %w( XXE ),
210
+ 'G' => %w( XXG G C I ),
211
+ 'B' => %w( YYG B M ),
212
+ 'D' => %w( GGG D ),
213
+ 'P' => %w( YGG P )
214
+ }.inject({}) do |map, (type, codes)|
215
+ codes.each { |code| map[code] = type }
216
+ map
217
+ end #:nodoc:
218
+
219
+ AVS_CUSTOM_MESSAGES = {
220
+ 'XXW' => 'Card number not on file.',
221
+ 'XXU' => 'Address information not verified for domestic transaction.',
222
+ 'XXE' => 'Address verification not allowed for card type.'
223
+ } #:nodoc:
224
+
225
+ # Create a new gateway.
226
+ #
227
+ # ==== Required
228
+ # * At least the live_url OR the software_id must be present.
229
+ # * <tt>:software_id</tt> -- 8 character software id
230
+ # OR
231
+ # * <tt>:test_url</tt> -- full url for testing
232
+ # * <tt>:live_url</tt> -- full url for live/production
233
+ #
234
+ # ==== Optional
235
+ # * <tt>:soap_response</tt> -- set to +true+ to add :soap_response to the params hash containing the entire soap xml message
236
+ #
237
+ def initialize(options = {})
238
+ requires!(options, :login, :password)
239
+
240
+ if options[:software_id]
241
+ self.live_url = "#{LIVE_URL_BASE}#{options[:software_id].to_s}"
242
+ self.test_url = "#{TEST_URL_BASE}#{options[:software_id].to_s}"
243
+ else
244
+ self.live_url = options[:live_url].to_s
245
+ self.test_url = options[:test_url].to_s if options[:test_url]
246
+ end
247
+
248
+ super
249
+ end
250
+
251
+ # Standard Gateway Methods ======================================
252
+
253
+ # Make a purchase with a credit card. (Authorize and
254
+ # capture for settlement.)
255
+ #
256
+ # Note: See run_transaction for additional options.
257
+ #
258
+ def purchase(money, creditcard, options={})
259
+ run_sale(options.merge!(:amount => money, :payment_method => creditcard))
260
+ end
261
+
262
+ # Authorize an amount on a credit card or account.
263
+ #
264
+ # Note: See run_transaction for additional options.
265
+ #
266
+ def authorize(money, creditcard, options={})
267
+ run_auth_only(options.merge!(:amount => money, :payment_method => creditcard))
268
+ end
269
+
270
+ # Capture an authorized transaction.
271
+ #
272
+ # Note: See run_transaction for additional options.
273
+ #
274
+ def capture(money, identification, options={})
275
+ capture_transaction(options.merge!(:amount => money, :reference_number => identification))
276
+ end
277
+
278
+ # Void a previous transaction that has not been settled.
279
+ #
280
+ # Note: See run_transaction for additional options.
281
+ #
282
+ def void(identification, options={})
283
+ void_transaction(options.merge!(:reference_number => identification))
284
+ end
285
+
286
+ # Refund a previous transaction.
287
+ #
288
+ # Note: See run_transaction for additional options.
289
+ #
290
+ def refund(money, identification, options={})
291
+ refund_transaction(options.merge!(:amount => money, :reference_number => identification))
292
+ end
293
+
294
+ def credit(money, identification, options={})
295
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
296
+ refund(money, identification, options)
297
+ end
298
+
299
+ # Customer ======================================================
300
+
301
+ # Add a customer.
302
+ #
303
+ # ==== Options
304
+ # * <tt>:id</tt> -- merchant assigned id
305
+ # * <tt>:notes</tt> -- notes about customer
306
+ # * <tt>:data</tt> -- base64 data about customer
307
+ # * <tt>:url</tt> -- customer website
308
+ # * <tt>:billing_address</tt> -- usual options
309
+ # * <tt>:payment_methods</tt> -- array of payment method hashes.
310
+ # * <tt>:method</tt> -- credit_card or check
311
+ # * <tt>:name</tt> -- optional name/label for the method
312
+ # * <tt>:sort</tt> -- optional integer value specifying the backup sort order, 0 is default
313
+ #
314
+ # ==== Recurring Options
315
+ # * <tt>:enabled</tt> -- +true+ enables recurring
316
+ # * <tt>:schedule</tt> -- daily, weekly, bi-weekly (every two weeks), monthly, bi-monthly (every two months), quarterly, bi-annually (every six months), annually, first of month, last day of month
317
+ # * <tt>:number_left</tt> -- number of payments left; -1 for unlimited
318
+ # * <tt>:next</tt> -- date of next payment (Date/Time)
319
+ # * <tt>:amount</tt> -- amount of recurring payment
320
+ # * <tt>:tax</tt> -- tax portion of amount
321
+ # * <tt>:currency</tt> -- numeric currency code
322
+ # * <tt>:description</tt> -- description of transaction
323
+ # * <tt>:order_id</tt> -- transaction order id
324
+ # * <tt>:user</tt> -- merchant username assigned to transaction
325
+ # * <tt>:source</tt> -- name of source key assigned to billing
326
+ # * <tt>:send_receipt</tt> -- +true+ to send client a receipt
327
+ # * <tt>:receipt_note</tt> -- leave a note on the receipt
328
+ #
329
+ # ==== Point of Sale Options
330
+ # * <tt>:price_tier</tt> -- name of customer price tier
331
+ # * <tt>:tax_class</tt> -- tax class
332
+ # * <tt>:lookup_code</tt> -- lookup code from customer/member id card; barcode or magnetic stripe; can be assigned by merchant; defaults to system assigned if blank
333
+ #
334
+ # ==== Response
335
+ # * <tt>#message</tt> -- customer number assigned by gateway
336
+ #
337
+ def add_customer(options={})
338
+ request = build_request(__method__, options)
339
+ commit(__method__, request)
340
+ end
341
+
342
+ # Update a customer by replacing all of the customer details.
343
+ #
344
+ # ==== Required
345
+ # * <tt>:customer_number</tt> -- customer to update
346
+ #
347
+ # ==== Options
348
+ # * Same as add_customer
349
+ #
350
+ def update_customer(options={})
351
+ requires! options, :customer_number
352
+
353
+ request = build_request(__method__, options)
354
+ commit(__method__, request)
355
+ end
356
+
357
+ # Enable a customer for recurring billing.
358
+ #
359
+ # Note: Customer does not need to have all recurring parameters to succeed.
360
+ #
361
+ # ==== Required
362
+ # * <tt>:customer_number</tt>
363
+ #
364
+ def enable_customer(options={})
365
+ requires! options, :customer_number
366
+
367
+ request = build_request(__method__, options)
368
+ commit(__method__, request)
369
+ end
370
+
371
+ # Disable a customer for recurring billing.
372
+ #
373
+ # ==== Required
374
+ # * <tt>:customer_number</tt>
375
+ #
376
+ def disable_customer(options={})
377
+ requires! options, :customer_number
378
+
379
+ request = build_request(__method__, options)
380
+ commit(__method__, request)
381
+ end
382
+
383
+ # Add a payment method to a customer.
384
+ #
385
+ # ==== Required
386
+ # * <tt>:customer_number</tt> -- number returned by add_customer response.message
387
+ # * <tt>:payment_method</tt>
388
+ # * <tt>:method</tt> -- credit_card or check
389
+ # * <tt>:name</tt> -- optional name/label for the method
390
+ # * <tt>:sort</tt> -- an integer value specifying the backup sort order, 0 is default
391
+ #
392
+ # ==== Optional
393
+ # * <tt>:make_default</tt> -- set +true+ to make default
394
+ # * <tt>:verify</tt> -- set +true+ to run auth_only verification; throws fault if cannot verify
395
+ #
396
+ # ==== Response
397
+ # * <tt>#message</tt> -- method_id of new customer payment method
398
+ #
399
+ def add_customer_payment_method(options={})
400
+ requires! options, :customer_number
401
+
402
+ request = build_request(__method__, options)
403
+ commit(__method__, request)
404
+ end
405
+
406
+ # Retrive all of the payment methods belonging to a customer
407
+ #
408
+ # ==== Required
409
+ # * <tt>:customer_number</tt>
410
+ #
411
+ # ==== Response
412
+ # * <tt>#message</tt> -- either a single hash or an array of hashes of payment methods
413
+ #
414
+ def get_customer_payment_methods(options={})
415
+ requires! options, :customer_number
416
+
417
+ request = build_request(__method__, options)
418
+ commit(__method__, request)
419
+ end
420
+
421
+ # Retrive one of the payment methods belonging to a customer
422
+ #
423
+ # ==== Required
424
+ # * <tt>:customer_number</tt>
425
+ # * <tt>:method_id</tt>
426
+ #
427
+ # ==== Response
428
+ # * <tt>#message</tt> -- hash of payment method
429
+ #
430
+ def get_customer_payment_method(options={})
431
+ requires! options, :customer_number, :method_id
432
+
433
+ request = build_request(__method__, options)
434
+ commit(__method__, request)
435
+ end
436
+
437
+ # Update a customer payment method.
438
+ #
439
+ # ==== Required
440
+ # * <tt>:method_id</tt> -- method_id to update
441
+ #
442
+ # ==== Options
443
+ # * <tt>:method</tt> -- credit_card or check
444
+ # * <tt>:name</tt> -- optional name/label for the method
445
+ # * <tt>:sort</tt> -- an integer value specifying the backup sort order, 0 is default
446
+ # * <tt>:verify</tt> -- set +true+ to run auth_only verification; throws fault if cannot verify
447
+ #
448
+ # ==== Response
449
+ # * <tt>#message</tt> -- hash of payment method
450
+ #
451
+ def update_customer_payment_method(options={})
452
+ requires! options, :method_id
453
+
454
+ request = build_request(__method__, options)
455
+ commit(__method__, request)
456
+ end
457
+
458
+ # Delete one the payment methods belonging to a customer
459
+ #
460
+ # ==== Required
461
+ # * <tt>:customer_number</tt>
462
+ # * <tt>:method_id</tt>
463
+ #
464
+ def delete_customer_payment_method(options={})
465
+ requires! options, :customer_number, :method_id
466
+
467
+ request = build_request(__method__, options)
468
+ commit(__method__, request)
469
+ end
470
+
471
+ # Delete a customer.
472
+ #
473
+ # ==== Required
474
+ # * <tt>:customer_number</tt>
475
+ #
476
+ def delete_customer(options={})
477
+ requires! options, :customer_number
478
+
479
+ request = build_request(__method__, options)
480
+ commit(__method__, request)
481
+ end
482
+
483
+ # Run a transaction for an existing customer in the database.
484
+ #
485
+ # ==== Required Options
486
+ # * <tt>:customer_number</tt> -- gateway assigned identifier
487
+ # * <tt>:command</tt> -- Sale, AuthOnly, Credit, Check, CheckCredit
488
+ # * <tt>:amount</tt> -- total amount
489
+ #
490
+ # ==== Options
491
+ # * <tt>:method_id</tt> -- which payment method to use, 0/nil/omitted for default method
492
+ # * <tt>:ignore_duplicate</tt> -- +true+ overrides duplicate transaction
493
+ # * <tt>:client_ip</tt> -- client ip address
494
+ # * <tt>:customer_receipt</tt> -- +true+, sends receipt to customer. active_merchant defaults to +false+
495
+ # * <tt>:customer_email</tt> -- specify if different than customer record
496
+ # * <tt>:customer_template</tt> -- name of template
497
+ # * <tt>:merchant_receipt</tt> -- +true+, sends receipt to merchant. active_merchant defaults to +false+
498
+ # * <tt>:merchant_email</tt> -- required if :merchant_receipt set to +true+
499
+ # * <tt>:merchant_template</tt> -- name of template
500
+ # * <tt>:recurring</tt> -- defaults to +false+ *see documentation*
501
+ # * <tt>:verification_value</tt> -- pci forbids storage of this value, only required for CVV2 validation
502
+ # * <tt>:software</tt> -- active_merchant sets to required gateway option value
503
+ # * <tt>:line_items</tt> -- XXX not implemented yet
504
+ # * <tt>:custom_fields</tt> -- XXX not implemented yet
505
+ #
506
+ # ==== Transaction Options
507
+ # * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
508
+ # * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
509
+ # * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
510
+ # * <tt>:clerk</tt> -- sales clerk
511
+ # * <tt>:terminal</tt> -- terminal name
512
+ # * <tt>:table</tt> -- table name/number
513
+ # * <tt>:description</tt> -- description
514
+ # * <tt>:comments</tt> -- comments
515
+ # * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
516
+ # * <tt>:currency</tt> -- numeric currency code
517
+ # * <tt>:tax</tt> -- tax portion of amount
518
+ # * <tt>:tip</tt> -- tip portion of amount
519
+ # * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
520
+ # * <tt>:shipping</tt> -- shipping portion of amount
521
+ # * <tt>:discount</tt> -- amount of discount
522
+ # * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
523
+ #
524
+ # ==== Response
525
+ # * <tt>#message</tt> -- transaction response hash
526
+ #
527
+ def run_customer_transaction(options={})
528
+ requires! options, :customer_number, :command, :amount
529
+
530
+ request = build_request(__method__, options)
531
+ commit(__method__, request)
532
+ end
533
+
534
+ # Transactions ==================================================
535
+
536
+ # Run a transaction.
537
+ #
538
+ # Note: run_sale, run_auth_only, run_credit, run_check_sale, run_check_credit
539
+ # methods are also available. Each takes the same options as
540
+ # run_transaction, but the :command option is not required.
541
+ #
542
+ # Recurring Note: If recurring options are included USA ePay will create a
543
+ # new customer record with the supplied information. The customer number
544
+ # will be returned in the response.
545
+ #
546
+ # ==== Options
547
+ # * <tt>:payment_method</tt> -- credit_card or check
548
+ # * <tt>:command</tt> -- sale, credit, void, creditvoid, authonly, capture, postauth, check, checkcredit; defaults to sale; only required for run_transaction when other than sale
549
+ # * <tt>:reference_number</tt> -- for the original transaction; obtained by sale or authonly
550
+ # * <tt>:authorization_code</tt> -- required for postauth; obtained offline
551
+ # * <tt>:ignore_duplicate</tt> -- set +true+ if you want to override the duplicate transaction handling
552
+ # * <tt>:account_holder</tt> -- name of account holder
553
+ # * <tt>:customer_id</tt> -- merchant assigned id
554
+ # * <tt>:customer_receipt</tt> -- set +true+ to email receipt to billing email address
555
+ # * <tt>:customer_template</tt> -- name of template
556
+ # * <tt>:software</tt> -- stamp merchant software version for tracking
557
+ # * <tt>:billing_address</tt> -- see UsaEpayCimGateway documentation for all address fields
558
+ # * <tt>:shipping_address</tt> -- see UsaEpayCimGateway documentation for all address fields
559
+ # * <tt>:recurring</tt> -- used for recurring billing transactions
560
+ # * <tt>:schedule</tt> -- disabled, daily, weekly, bi-weekly (every two weeks), monthly, bi-monthly (every two months), quarterly, bi-annually (every six months), annually
561
+ # * <tt>:next</tt> -- date customer billed next (Date/Time)
562
+ # * <tt>:expire</tt> -- date the recurring transactions end (Date/Time)
563
+ # * <tt>:number_left</tt> -- transactions remaining in billing cycle
564
+ # * <tt>:amount</tt> -- amount to be billed each recurring transaction
565
+ # * <tt>:enabled</tt> -- states if currently active
566
+ # * <tt>:line_items</tt> -- XXX not implemented yet
567
+ # * <tt>:custom_fields</tt> -- XXX not implemented yet
568
+ #
569
+ # ==== Transaction Options
570
+ # * <tt>:amount</tt> -- total amount
571
+ # * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
572
+ # * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
573
+ # * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
574
+ # * <tt>:clerk</tt> -- sales clerk
575
+ # * <tt>:terminal</tt> -- terminal name
576
+ # * <tt>:table</tt> -- table name/number
577
+ # * <tt>:description</tt> -- description
578
+ # * <tt>:comments</tt> -- comments
579
+ # * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
580
+ # * <tt>:currency</tt> -- numeric currency code
581
+ # * <tt>:tax</tt> -- tax portion of amount
582
+ # * <tt>:tip</tt> -- tip portion of amount
583
+ # * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
584
+ # * <tt>:shipping</tt> -- shipping portion of amount
585
+ # * <tt>:discount</tt> -- amount of discount
586
+ # * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
587
+ #
588
+ # ==== Response
589
+ # * <tt>#message</tt> -- transaction response hash
590
+ #
591
+ def run_transaction(options={})
592
+ request = build_request(__method__, options)
593
+ commit(__method__, request)
594
+ end
595
+
596
+ TRANSACTION_METHODS = [
597
+ :run_sale, :run_auth_only, :run_credit,
598
+ :run_check_sale, :run_check_credit
599
+ ] #:nodoc:
600
+
601
+ TRANSACTION_METHODS.each do |method|
602
+ define_method method do |options|
603
+ request = build_request(method, options)
604
+ commit(method, request)
605
+ end
606
+ end
607
+
608
+ # Post an authorization code obtained offline.
609
+ #
610
+ # ==== Required
611
+ # * <tt>:authorization_code</tt> -- obtained offline
612
+ #
613
+ # ==== Options
614
+ # * Same as run_transaction
615
+ #
616
+ # ==== Response
617
+ # * <tt>#message</tt> -- transaction response hash
618
+ #
619
+ def post_auth(options={})
620
+ requires! options, :authorization_code
621
+
622
+ request = build_request(__method__, options)
623
+ commit(__method__, request)
624
+ end
625
+
626
+ # Capture an authorized transaction and move it into the current batch
627
+ # for settlement.
628
+ #
629
+ # Note: Check with merchant bank for details/restrictions on differing
630
+ # amounts than the original authorization.
631
+ #
632
+ # ==== Required
633
+ # * <tt>:reference_number</tt>
634
+ #
635
+ # ==== Options
636
+ # * <tt>:amount</tt> -- may be different than original amount; 0 will void authorization
637
+ #
638
+ # ==== Response
639
+ # * <tt>#message</tt> -- transaction response hash
640
+ #
641
+ def capture_transaction(options={})
642
+ requires! options, :reference_number
643
+
644
+ request = build_request(__method__, options)
645
+ commit(__method__, request)
646
+ end
647
+
648
+ # Void a transaction.
649
+ #
650
+ # Note: Can only be voided before being settled.
651
+ #
652
+ # ==== Required
653
+ # * <tt>:reference_number</tt>
654
+ #
655
+ # ==== Response
656
+ # * <tt>#message</tt> -- transaction response hash
657
+ #
658
+ def void_transaction(options={})
659
+ requires! options, :reference_number
660
+
661
+ request = build_request(__method__, options)
662
+ commit(__method__, request)
663
+ end
664
+
665
+ # Refund transaction.
666
+ #
667
+ # Note: Required after a transaction has been settled. Refunds
668
+ # both credit card and check transactions.
669
+ #
670
+ # ==== Required
671
+ # * <tt>:reference_number</tt>
672
+ # * <tt>:amount</tt> -- amount to refund; 0 will refund original amount
673
+ #
674
+ # ==== Response
675
+ # * <tt>#message</tt> -- transaction response hash
676
+ #
677
+ def refund_transaction(options={})
678
+ requires! options, :reference_number, :amount
679
+
680
+ request = build_request(__method__, options)
681
+ commit(__method__, request)
682
+ end
683
+
684
+ # Override transaction flagged for manager approval.
685
+ #
686
+ # Note: Checks only!
687
+ #
688
+ # ==== Required
689
+ # * <tt>:reference_number</tt>
690
+ #
691
+ # ==== Options
692
+ # * <tt>:reason</tt>
693
+ #
694
+ # ==== Response
695
+ # * <tt>#message</tt> -- transaction response hash
696
+ #
697
+ def override_transaction(options={})
698
+ requires! options, :reference_number
699
+
700
+ request = build_request(__method__, options)
701
+ commit(__method__, request)
702
+ end
703
+
704
+ # Quick Transactions ============================================
705
+
706
+ # Run a sale transaction based off of a past transaction.
707
+ #
708
+ # Transfers referenced transaction's payment method to this
709
+ # transaction. As of 6/2011, USA ePay blocks credit card numbers
710
+ # at 3 years.
711
+ #
712
+ # ==== Required
713
+ # * <tt>:reference_number</tt> -- transaction to reference payment from
714
+ # * <tt>:amount</tt> -- total amount
715
+ #
716
+ # ==== Options
717
+ # * <tt>:authorize_only</tt> -- set +true+ if you just want to authorize
718
+ #
719
+ # ==== Transaction Options
720
+ # * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
721
+ # * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
722
+ # * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
723
+ # * <tt>:clerk</tt> -- sales clerk
724
+ # * <tt>:terminal</tt> -- terminal name
725
+ # * <tt>:table</tt> -- table name/number
726
+ # * <tt>:description</tt> -- description
727
+ # * <tt>:comments</tt> -- comments
728
+ # * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
729
+ # * <tt>:currency</tt> -- numeric currency code
730
+ # * <tt>:tax</tt> -- tax portion of amount
731
+ # * <tt>:tip</tt> -- tip portion of amount
732
+ # * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
733
+ # * <tt>:shipping</tt> -- shipping portion of amount
734
+ # * <tt>:discount</tt> -- amount of discount
735
+ # * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
736
+ #
737
+ # ==== Response
738
+ # * <tt>#message</tt> -- transaction response hash
739
+ #
740
+ def run_quick_sale(options={})
741
+ requires! options, :reference_number, :amount
742
+
743
+ request = build_request(__method__, options)
744
+ commit(__method__, request)
745
+ end
746
+
747
+ # Run a credit based off of a past transaction.
748
+ #
749
+ # Transfers referenced transaction's payment method to this
750
+ # transaction. As of 6/2011, USA ePay blocks credit card numbers
751
+ # at 3 years.
752
+ #
753
+ # ==== Required
754
+ # * <tt>:reference_number</tt> -- transaction to reference payment from
755
+ #
756
+ # ==== Transaction Options
757
+ # * <tt>:amount</tt> -- total amount
758
+ # * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
759
+ # * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
760
+ # * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
761
+ # * <tt>:clerk</tt> -- sales clerk
762
+ # * <tt>:terminal</tt> -- terminal name
763
+ # * <tt>:table</tt> -- table name/number
764
+ # * <tt>:description</tt> -- description
765
+ # * <tt>:comments</tt> -- comments
766
+ # * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
767
+ # * <tt>:currency</tt> -- numeric currency code
768
+ # * <tt>:tax</tt> -- tax portion of amount
769
+ # * <tt>:tip</tt> -- tip portion of amount
770
+ # * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
771
+ # * <tt>:shipping</tt> -- shipping portion of amount
772
+ # * <tt>:discount</tt> -- amount of discount
773
+ # * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
774
+ #
775
+ # ==== Response
776
+ # * <tt>#message</tt> -- transaction response hash
777
+ #
778
+ def run_quick_credit(options={})
779
+ requires! options, :reference_number
780
+
781
+ request = build_request(__method__, options)
782
+ commit(__method__, request)
783
+ end
784
+
785
+ # Transaction Status ============================================
786
+
787
+ # Retrieve details of a specified transaction.
788
+ #
789
+ # ==== Required
790
+ # * <tt>:reference_number</tt>
791
+ #
792
+ # ==== Response
793
+ # * <tt>#message</tt> -- transaction hash
794
+ #
795
+ def get_transaction(options={})
796
+ requires! options, :reference_number
797
+
798
+ request = build_request(__method__, options)
799
+ commit(__method__, request)
800
+ end
801
+
802
+ # Check status of a transaction.
803
+ #
804
+ # ==== Required
805
+ # * <tt>:reference_number</tt>
806
+ #
807
+ # ==== Response
808
+ # * <tt>response.success</tt> -- success of the referenced transaction
809
+ # * <tt>response.message</tt> -- message of the referenced transaction
810
+ # * <tt>response.authorization</tt> -- same as :reference_number in options
811
+ #
812
+ def get_transaction_status(options={})
813
+ requires! options, :reference_number
814
+
815
+ request = build_request(__method__, options)
816
+ commit(__method__, request)
817
+ end
818
+
819
+ # Check status of a transaction (custom).
820
+ #
821
+ # ==== Required
822
+ # * <tt>:reference_number</tt>
823
+ # * <tt>:fields</tt> -- string array of fields to retrieve
824
+ # * <tt>Response.AuthCode</tt>
825
+ # * <tt>Response.AvsResult</tt>
826
+ # * <tt>Response.AvsResultCode</tt>
827
+ # * <tt>Response.BatchNum</tt>
828
+ # * <tt>Response.CardCodeResult</tt>
829
+ # * <tt>Response.CardCodeResultCode</tt>
830
+ # * <tt>Response.ConversionRate</tt>
831
+ # * <tt>Response.ConvertedAmount</tt>
832
+ # * <tt>Response.ConvertedAmountCurrency</tt>
833
+ # * <tt>Response.Error</tt>
834
+ # * <tt>Response.ErrorCode</tt>
835
+ # * <tt>Response.RefNum</tt>
836
+ # * <tt>Response.Result</tt>
837
+ # * <tt>Response.ResultCode</tt>
838
+ # * <tt>Response.Status</tt>
839
+ # * <tt>Response.StatusCode</tt>
840
+ # * <tt>CheckTrace.TrackingNum</tt>
841
+ # * <tt>CheckTrace.Effective</tt>
842
+ # * <tt>CheckTrace.Processed</tt>
843
+ # * <tt>CheckTrace.Settled</tt>
844
+ # * <tt>CheckTrace.Returned</tt>
845
+ # * <tt>CheckTrace.BankNote</tt>
846
+ # * <tt>DateTime</tt>
847
+ # * <tt>AccountHolder</tt>
848
+ # * <tt>Details.Invoice</tt>
849
+ # * <tt>Details.PoNum</tt>
850
+ # * <tt>Details.OrderID</tt>
851
+ # * <tt>Details.Clerk</tt>
852
+ # * <tt>Details.Terminal</tt>
853
+ # * <tt>Details.Table</tt>
854
+ # * <tt>Details.Description</tt>
855
+ # * <tt>Details.Amount</tt>
856
+ # * <tt>Details.Currency</tt>
857
+ # * <tt>Details.Tax</tt>
858
+ # * <tt>Details.Tip</tt>
859
+ # * <tt>Details.NonTax</tt>
860
+ # * <tt>Details.Shipping</tt>
861
+ # * <tt>Details.Discount</tt>
862
+ # * <tt>Details.Subtotal</tt>
863
+ # * <tt>CreditCardData.CardType</tt>
864
+ # * <tt>CreditCardData.CardNumber</tt>
865
+ # * <tt>CreditCardData.CardExpiration</tt>
866
+ # * <tt>CreditCardData.CardCode</tt>
867
+ # * <tt>CreditCardData.AvsStreet</tt>
868
+ # * <tt>CreditCardData.AvsZip</tt>
869
+ # * <tt>CreditCardData.CardPresent</tt>
870
+ # * <tt>CheckData.CheckNumber</tt>
871
+ # * <tt>CheckData.Routing</tt>
872
+ # * <tt>CheckData.Account</tt>
873
+ # * <tt>CheckData.SSN</tt>
874
+ # * <tt>CheckData.DriversLicense</tt>
875
+ # * <tt>CheckData.DriversLicenseState</tt>
876
+ # * <tt>CheckData.RecordType</tt>
877
+ # * <tt>User</tt>
878
+ # * <tt>Source</tt>
879
+ # * <tt>ServerIP</tt>
880
+ # * <tt>ClientIP</tt>
881
+ # * <tt>CustomerID</tt>
882
+ # * <tt>BillingAddress.FirstName</tt>
883
+ # * <tt>BillingAddress.LastName</tt>
884
+ # * <tt>BillingAddress.Company</tt>
885
+ # * <tt>BillingAddress.Street</tt>
886
+ # * <tt>BillingAddress.Street2</tt>
887
+ # * <tt>BillingAddress.City</tt>
888
+ # * <tt>BillingAddress.State</tt>
889
+ # * <tt>BillingAddress.Zip</tt>
890
+ # * <tt>BillingAddress.Country</tt>
891
+ # * <tt>BillingAddress.Phone</tt>
892
+ # * <tt>BillingAddress.Fax</tt>
893
+ # * <tt>BillingAddress.Email</tt>
894
+ # * <tt>ShippingAddress.FirstName</tt>
895
+ # * <tt>ShippingAddress.LastName</tt>
896
+ # * <tt>ShippingAddress.Company</tt>
897
+ # * <tt>ShippingAddress.Street</tt>
898
+ # * <tt>ShippingAddress.Street2</tt>
899
+ # * <tt>ShippingAddress.City</tt>
900
+ # * <tt>ShippingAddress.State</tt>
901
+ # * <tt>ShippingAddress.Zip</tt>
902
+ # * <tt>ShippingAddress.Country</tt>
903
+ # * <tt>ShippingAddress.Phone</tt>
904
+ # * <tt>ShippingAddress.Fax</tt>
905
+ # * <tt>ShippingAddress.Email</tt>
906
+ #
907
+ # ==== Response
908
+ # * <tt>#message</tt> -- hash; keys are the field values
909
+ #
910
+ def get_transaction_custom(options={})
911
+ requires! options, :reference_number, :fields
912
+
913
+ request = build_request(__method__, options)
914
+ commit(__method__, request)
915
+ end
916
+
917
+ # Check status of a check transaction.
918
+ #
919
+ # ==== Required
920
+ # * <tt>:reference_number</tt>
921
+ #
922
+ # ==== Response
923
+ # * <tt>#message</tt> -- check trace hash
924
+ #
925
+ def get_check_trace(options={})
926
+ requires! options, :reference_number
927
+
928
+ request = build_request(__method__, options)
929
+ commit(__method__, request)
930
+ end
931
+
932
+ # Account =======================================================
933
+
934
+ # Retrieve merchant account details
935
+ #
936
+ # ==== Response
937
+ # * <tt>#message</tt> -- account hash
938
+ #
939
+ def get_account_details
940
+ request = build_request(__method__)
941
+ commit(__method__, request)
942
+ end
943
+
944
+ # Builders ======================================================
945
+
946
+ private
947
+
948
+ # Build soap header, etc.
949
+ def build_request(action, options = {})
950
+ soap = Builder::XmlMarkup.new
951
+ soap.instruct!(:xml, :version => '1.0', :encoding => 'utf-8')
952
+ soap.tag! "SOAP-ENV:Envelope",
953
+ 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
954
+ 'xmlns:ns1' => 'urn:usaepay',
955
+ 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
956
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
957
+ 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
958
+ 'SOAP-ENV:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/' do
959
+ soap.tag! "SOAP-ENV:Body" do
960
+ send("build_#{action}", soap, options)
961
+ end
962
+ end
963
+ soap.target!
964
+ end
965
+
966
+ # Build generic tag.
967
+ def build_tag(soap, type, tag, value)
968
+ soap.tag!(tag, value, 'xsi:type' => "xsd:#{type}") if value != nil
969
+ end
970
+
971
+ # Build token.
972
+ def build_token(soap, options)
973
+ seed = SecureRandom.base64(32)
974
+ hash = Digest::SHA1.hexdigest("#{@options[:login]}#{seed}#{@options[:password].to_s.strip}")
975
+ soap.Token 'xsi:type' => 'ns1:ueSecurityToken' do
976
+ build_tag soap, :string, 'ClientIP', options[:client_ip]
977
+ soap.PinHash 'xsi:type' => 'ns1:ueHash' do
978
+ build_tag soap, :string, "HashValue", hash
979
+ build_tag soap, :string, "Seed", seed
980
+ build_tag soap, :string, "Type", 'sha1'
981
+ end
982
+ build_tag soap, :string, 'SourceKey', @options[:login]
983
+ end
984
+ end
985
+
986
+ # Customer ======================================================
987
+
988
+ def build_add_customer(soap, options)
989
+ soap.tag! "ns1:addCustomer" do
990
+ build_token soap, options
991
+ build_customer_data soap, options
992
+ build_tag soap, :double, 'Amount', amount(options[:amount])
993
+ build_tag soap, :double, 'Tax', amount(options[:tax])
994
+ build_tag soap, :string, 'Next', options[:next].strftime("%Y-%m-%d") if options[:next]
995
+ end
996
+ end
997
+
998
+ def build_customer(soap, options, type, add_customer_data=false)
999
+ soap.tag! "ns1:#{type}" do
1000
+ build_token soap, options
1001
+ build_tag soap, :integer, 'CustNum', options[:customer_number]
1002
+ build_customer_data soap, options if add_customer_data
1003
+ end
1004
+ end
1005
+
1006
+ def build_update_customer(soap, options)
1007
+ build_customer(soap, options, 'updateCustomer', true)
1008
+ end
1009
+
1010
+ def build_enable_customer(soap, options)
1011
+ build_customer(soap, options, 'enableCustomer')
1012
+ end
1013
+
1014
+ def build_disable_customer(soap, options)
1015
+ build_customer(soap, options, 'disableCustomer')
1016
+ end
1017
+
1018
+ def build_delete_customer(soap, options)
1019
+ build_customer(soap, options, 'deleteCustomer')
1020
+ end
1021
+
1022
+ def build_add_customer_payment_method(soap, options)
1023
+ soap.tag! "ns1:addCustomerPaymentMethod" do
1024
+ build_token soap, options
1025
+ build_tag soap, :integer, 'CustNum', options[:customer_number]
1026
+ build_customer_payment_methods soap, options
1027
+ build_tag soap, :boolean, 'MakeDefault', options[:make_default]
1028
+ build_tag soap, :boolean, 'Verify', options[:verify]
1029
+ end
1030
+ end
1031
+
1032
+ def build_get_customer_payment_method(soap, options)
1033
+ soap.tag! 'ns1:getCustomerPaymentMethod' do
1034
+ build_token soap, options
1035
+ build_tag soap, :integer, 'CustNum', options[:customer_number]
1036
+ build_tag soap, :integer, 'MethodID', options[:method_id]
1037
+ end
1038
+ end
1039
+
1040
+ def build_get_customer_payment_methods(soap, options)
1041
+ build_customer(soap, options, 'getCustomerPaymentMethods')
1042
+ end
1043
+
1044
+ def build_update_customer_payment_method(soap, options)
1045
+ soap.tag! 'ns1:updateCustomerPaymentMethod' do
1046
+ build_token soap, options
1047
+ build_customer_payment_methods soap, options
1048
+ build_tag soap, :boolean, 'Verify', options[:verify]
1049
+ end
1050
+ end
1051
+
1052
+ def build_delete_customer_payment_method(soap, options)
1053
+ soap.tag! "ns1:deleteCustomerPaymentMethod" do
1054
+ build_token soap, options
1055
+ build_tag soap, :integer, 'Custnum', options[:customer_number]
1056
+ build_tag soap, :integer, 'PaymentMethodID', options[:method_id]
1057
+ end
1058
+ end
1059
+
1060
+ def build_run_customer_transaction(soap, options)
1061
+ soap.tag! "ns1:runCustomerTransaction" do
1062
+ build_token soap, options
1063
+ build_tag soap, :integer, 'CustNum', options[:customer_number]
1064
+ build_tag soap, :integer, 'PaymentMethodID', options[:method_id] || 0
1065
+ build_customer_transaction soap, options
1066
+ end
1067
+ end
1068
+
1069
+ # Transactions ==================================================
1070
+
1071
+ def build_run_transaction(soap, options)
1072
+ soap.tag! 'ns1:runTransaction' do
1073
+ build_token soap, options
1074
+ build_transaction_request_object soap, options, 'Parameters'
1075
+ end
1076
+ end
1077
+
1078
+ def build_run_sale(soap, options)
1079
+ soap.tag! 'ns1:runSale' do
1080
+ build_token soap, options
1081
+ build_transaction_request_object soap, options
1082
+ end
1083
+ end
1084
+
1085
+ def build_run_auth_only(soap, options)
1086
+ soap.tag! 'ns1:runAuthOnly' do
1087
+ build_token soap, options
1088
+ build_transaction_request_object soap, options
1089
+ end
1090
+ end
1091
+
1092
+ def build_run_credit(soap, options)
1093
+ soap.tag! 'ns1:runCredit' do
1094
+ build_token soap, options
1095
+ build_transaction_request_object soap, options
1096
+ end
1097
+ end
1098
+
1099
+ def build_run_check_sale(soap, options)
1100
+ soap.tag! 'ns1:runCheckSale' do
1101
+ build_token soap, options
1102
+ build_transaction_request_object soap, options
1103
+ end
1104
+ end
1105
+
1106
+ def build_run_check_credit(soap, options)
1107
+ soap.tag! 'ns1:runCheckCredit' do
1108
+ build_token soap, options
1109
+ build_transaction_request_object soap, options
1110
+ end
1111
+ end
1112
+
1113
+ def build_post_auth(soap, options)
1114
+ soap.tag! 'ns1:postAuth' do
1115
+ build_token soap, options
1116
+ build_transaction_request_object soap, options
1117
+ end
1118
+ end
1119
+
1120
+ def build_run_quick_sale(soap, options)
1121
+ soap.tag! 'ns1:runQuickSale' do
1122
+ build_token soap, options
1123
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1124
+ build_transaction_detail soap, options
1125
+ build_tag soap, :boolean, 'AuthOnly', options[:authorize_only] || false
1126
+ end
1127
+ end
1128
+
1129
+ def build_run_quick_credit(soap, options)
1130
+ soap.tag! 'ns1:runQuickCredit' do
1131
+ build_token soap, options
1132
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1133
+ build_transaction_detail soap, options
1134
+ end
1135
+ end
1136
+
1137
+ def build_get_transaction(soap, options)
1138
+ soap.tag! "ns1:getTransaction" do
1139
+ build_token soap, options
1140
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1141
+ end
1142
+ end
1143
+
1144
+ def build_get_transaction_status(soap, options)
1145
+ soap.tag! "ns1:getTransactionStatus" do
1146
+ build_token soap, options
1147
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1148
+ end
1149
+ end
1150
+
1151
+ def build_get_transaction_custom(soap, options)
1152
+ soap.tag! "ns1:getTransactionCustom" do
1153
+ build_token soap, options
1154
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1155
+ build_transaction_field_array soap, options
1156
+ end
1157
+ end
1158
+
1159
+ def build_get_check_trace(soap, options)
1160
+ soap.tag! "ns1:getCheckTrace" do
1161
+ build_token soap, options
1162
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1163
+ end
1164
+ end
1165
+
1166
+ def build_capture_transaction(soap, options)
1167
+ soap.tag! "ns1:captureTransaction" do
1168
+ build_token soap, options
1169
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1170
+ build_tag soap, :double, 'Amount', amount(options[:amount])
1171
+ end
1172
+ end
1173
+
1174
+ def build_void_transaction(soap, options)
1175
+ soap.tag! "ns1:voidTransaction" do
1176
+ build_token soap, options
1177
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1178
+ end
1179
+ end
1180
+
1181
+ def build_refund_transaction(soap, options)
1182
+ soap.tag! "ns1:refundTransaction" do
1183
+ build_token soap, options
1184
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1185
+ build_tag soap, :integer, 'Amount', amount(options[:amount])
1186
+ end
1187
+ end
1188
+
1189
+ def build_override_transaction(soap, options)
1190
+ soap.tag! "ns1:overrideTransaction" do
1191
+ build_token soap, options
1192
+ build_tag soap, :integer, 'RefNum', options[:reference_number]
1193
+ build_tag soap, :string, 'Reason', options[:reason]
1194
+ end
1195
+ end
1196
+
1197
+ # Account =======================================================
1198
+
1199
+ def build_get_account_details(soap, options)
1200
+ soap.tag! "ns1:getAccountDetails" do
1201
+ build_token soap, options
1202
+ end
1203
+ end
1204
+
1205
+ # Customer Helpers ==============================================
1206
+
1207
+ def build_customer_data(soap, options)
1208
+ soap.CustomerData 'xsi:type' => 'ns1:CustomerObject' do
1209
+ CUSTOMER_OPTIONS.each do |k,v|
1210
+ build_tag soap, v[0], v[1], options[k]
1211
+ end
1212
+ build_billing_address soap, options
1213
+ build_customer_payments soap, options
1214
+ build_custom_fields soap, options
1215
+ end
1216
+ end
1217
+
1218
+ def build_customer_payments(soap, options)
1219
+ if options[:payment_methods]
1220
+ length = options[:payment_methods].length
1221
+ soap.PaymentMethods 'SOAP-ENC:arrayType' => "ns1:PaymentMethod[#{length}]",
1222
+ 'xsi:type' =>"ns1:PaymentMethodArray" do
1223
+ build_customer_payment_methods soap, options
1224
+ end
1225
+ end
1226
+ end
1227
+
1228
+ def extract_methods_and_tag(options)
1229
+ case
1230
+ when options[:payment_method] && !options[:payment_methods]
1231
+ payment_methods = [options[:payment_method]]
1232
+ tag_name = 'PaymentMethod'
1233
+ when options[:payment_methods] && !options[:payment_method]
1234
+ payment_methods = options[:payment_methods]
1235
+ tag_name = 'item'
1236
+ else
1237
+ payment_methods = [options]
1238
+ tag_name = 'PaymentMethod'
1239
+ end
1240
+ [payment_methods, tag_name]
1241
+ end
1242
+
1243
+ def build_credit_card_or_check(soap, payment_method)
1244
+ case
1245
+ when payment_method[:method].kind_of?(ActiveMerchant::Billing::CreditCard)
1246
+ build_tag soap, :string, 'CardNumber', payment_method[:method].number
1247
+ build_tag soap, :string, 'CardExpiration',
1248
+ "#{"%02d" % payment_method[:method].month}#{payment_method[:method].year.to_s[-2..-1]}"
1249
+ if options[:billing_address]
1250
+ build_tag soap, :string, 'AvsStreet', options[:billing_address][:address1]
1251
+ build_tag soap, :string, 'AvsZip', options[:billing_address][:zip]
1252
+ end
1253
+ build_tag soap, :string, 'CardCode', payment_method[:method].verification_value
1254
+ when payment_method[:method].kind_of?(ActiveMerchant::Billing::Check)
1255
+ build_tag soap, :string, 'Account', payment_method[:method].account_number
1256
+ build_tag soap, :string, 'Routing', payment_method[:method].routing_number
1257
+ unless payment_method[:method].account_type.nil?
1258
+ build_tag soap, :string, 'AccountType', payment_method[:method].account_type.capitalize
1259
+ end
1260
+ build_tag soap, :string, 'DriversLicense', options[:drivers_license]
1261
+ build_tag soap, :string, 'DriversLicenseState', options[:drivers_license_state]
1262
+ build_tag soap, :string, 'RecordType', options[:record_type]
1263
+ end
1264
+ end
1265
+
1266
+ def build_customer_payment_methods(soap, options)
1267
+ payment_methods, tag_name = extract_methods_and_tag(options)
1268
+ payment_methods.each do |payment_method|
1269
+ soap.tag! tag_name, 'xsi:type' => "ns1:PaymentMethod" do
1270
+ build_tag soap, :integer, 'MethodID', payment_method[:method_id]
1271
+ build_tag soap, :string, 'MethodType', payment_method[:type]
1272
+ build_tag soap, :string, 'MethodName', payment_method[:name]
1273
+ build_tag soap, :integer, 'SecondarySort', payment_method[:sort]
1274
+ build_credit_card_or_check(soap, payment_method)
1275
+ end
1276
+ end
1277
+ end
1278
+
1279
+ def build_customer_transaction(soap, options)
1280
+ soap.Parameters 'xsi:type' => "ns1:CustomerTransactionRequest" do
1281
+ build_transaction_detail soap, options
1282
+ CUSTOMER_TRANSACTION_REQUEST_OPTIONS.each do |k,v|
1283
+ build_tag soap, v[0], v[1], options[k]
1284
+ end
1285
+ build_custom_fields soap, options
1286
+ build_line_items soap, options
1287
+ end
1288
+ end
1289
+
1290
+ # Transaction Helpers ===========================================
1291
+
1292
+ def build_transaction_request_object(soap, options, name='Params')
1293
+ soap.tag! name, 'xsi:type' => "ns1:TransactionRequestObject" do
1294
+ TRANSACTION_REQUEST_OBJECT_OPTIONS.each do |k,v|
1295
+ build_tag soap, v[0], v[1], options[k]
1296
+ end
1297
+ case
1298
+ when options[:payment_method] == nil
1299
+ when options[:payment_method].kind_of?(ActiveMerchant::Billing::CreditCard)
1300
+ build_credit_card_data soap, options
1301
+ when options[:payment_method].kind_of?(ActiveMerchant::Billing::Check)
1302
+ build_check_data soap, options
1303
+ else
1304
+ raise ArgumentError, 'options[:payment_method] must be a CreditCard or Check'
1305
+ end
1306
+ build_transaction_detail soap, options
1307
+ build_billing_address soap, options
1308
+ build_shipping_address soap, options
1309
+ build_recurring_billing soap, options
1310
+ build_line_items soap, options
1311
+ build_custom_fields soap, options
1312
+ end
1313
+ end
1314
+
1315
+ def build_transaction_detail(soap, options)
1316
+ soap.Details 'xsi:type' => "ns1:TransactionDetail" do
1317
+ TRANSACTION_DETAIL_OPTIONS.each do |k,v|
1318
+ build_tag soap, v[0], v[1], options[k]
1319
+ end
1320
+ TRANSACTION_DETAIL_MONEY_OPTIONS.each do |k,v|
1321
+ build_tag soap, v[0], v[1], amount(options[k])
1322
+ end
1323
+ end
1324
+ end
1325
+
1326
+ def build_credit_card_data(soap, options)
1327
+ soap.CreditCardData 'xsi:type' => "ns1:CreditCardData" do
1328
+ build_tag soap, :string, 'CardNumber', options[:payment_method].number
1329
+ build_tag soap, :string, 'CardExpiration', build_card_expiration(options)
1330
+ if options[:billing_address]
1331
+ build_tag soap, :string, 'AvsStreet', options[:billing_address][:address1]
1332
+ build_tag soap, :string, 'AvsZip', options[:billing_address][:zip]
1333
+ end
1334
+ build_tag soap, :string, 'CardCode', options[:payment_method].verification_value
1335
+ build_tag soap, :boolean, 'CardPresent', options[:card_present] || false
1336
+ CREDIT_CARD_DATA_OPTIONS.each do |k,v|
1337
+ build_tag soap, v[0], v[1], options[k]
1338
+ end
1339
+ end
1340
+ end
1341
+
1342
+ def build_card_expiration(options)
1343
+ month = options[:payment_method].month
1344
+ year = options[:payment_method].year
1345
+ unless month.nil? || year.nil?
1346
+ "#{"%02d" % month}#{year.to_s[-2..-1]}"
1347
+ end
1348
+ end
1349
+
1350
+ def build_check_data(soap, options)
1351
+ soap.CheckData 'xsi:type' => "ns1:CheckData" do
1352
+ build_tag soap, :integer, 'CheckNumber', options[:payment_method].number
1353
+ build_tag soap, :string, 'Account', options[:payment_method].account_number
1354
+ build_tag soap, :string, 'Routing', options[:payment_method].routing_number
1355
+ build_tag soap, :string, 'AccountType', options[:payment_method].account_type.capitalize
1356
+ CHECK_DATA_OPTIONS.each do |k,v|
1357
+ build_tag soap, v[0], v[1], options[k]
1358
+ end
1359
+ end
1360
+ end
1361
+
1362
+ def build_recurring_billing(soap, options)
1363
+ if options[:recurring]
1364
+ soap.RecurringBilling 'xsi:type' => "ns1:RecurringBilling" do
1365
+ build_tag soap, :double, 'Amount', amount(options[:recurring][:amount])
1366
+ build_tag soap, :string, 'Next', options[:recurring][:next].strftime("%Y-%m-%d") if options[:recurring][:next]
1367
+ build_tag soap, :string, 'Expire', options[:recurring][:expire].strftime("%Y-%m-%d") if options[:recurring][:expire]
1368
+ RECURRING_BILLING_OPTIONS.each do |k,v|
1369
+ build_tag soap, v[0], v[1], options[:recurring][k]
1370
+ end
1371
+ end
1372
+ end
1373
+ end
1374
+
1375
+ def build_transaction_field_array(soap, options)
1376
+ soap.Fields 'SOAP-ENC:arryType' => "xsd:string[#{options[:fields].length}]", 'xsi:type' => 'ns1:stringArray' do
1377
+ options[:fields].each do |field|
1378
+ build_tag soap, :string, 'item', field
1379
+ end
1380
+ end
1381
+ end
1382
+
1383
+ # General Helpers ===============================================
1384
+
1385
+ def build_billing_address(soap, options)
1386
+ if options[:billing_address]
1387
+ if options[:billing_address][:name]
1388
+ name = options[:billing_address][:name].split(nil,2) # divide name
1389
+ options[:billing_address][:first_name], options[:billing_address][:last_name] = name[0], name[1]
1390
+ end
1391
+ soap.BillingAddress 'xsi:type' => "ns1:Address" do
1392
+ ADDRESS_OPTIONS.each do |k,v|
1393
+ build_tag soap, v[0], v[1], options[:billing_address][k]
1394
+ end
1395
+ end
1396
+ end
1397
+ end
1398
+
1399
+ def build_shipping_address(soap, options)
1400
+ if options[:shipping_address]
1401
+ if options[:shipping_address][:name]
1402
+ name = options[:shipping_address][:name].split(nil,2) # divide name
1403
+ options[:shipping_address][:first_name], options[:shipping_address][:last_name] = name[0], name[1]
1404
+ end
1405
+ soap.ShippingAddress 'xsi:type' => "ns1:Address" do
1406
+ ADDRESS_OPTIONS.each do |k,v|
1407
+ build_tag soap, v[0], v[1], options[:shipping_address][k]
1408
+ end
1409
+ end
1410
+ end
1411
+ end
1412
+
1413
+ def build_line_items(soap, options) # TODO
1414
+ end
1415
+
1416
+ def build_custom_fields(soap, options) # TODO
1417
+ end
1418
+
1419
+ # Request =======================================================
1420
+
1421
+ def commit(action, request)
1422
+ url = test? ? test_url : live_url
1423
+
1424
+ begin
1425
+ soap = ssl_post(url, request, "Content-Type" => "text/xml")
1426
+ rescue ActiveMerchant::ResponseError => error
1427
+ soap = error.response.body
1428
+ end
1429
+
1430
+ build_response(action, soap)
1431
+ end
1432
+
1433
+ def build_response(action, soap)
1434
+ response_params, success, message, authorization, avs, cvv = parse(action, soap)
1435
+
1436
+ response_params.merge!('soap_response' => soap) if @options[:soap_response]
1437
+
1438
+ Response.new(
1439
+ success,
1440
+ message,
1441
+ response_params,
1442
+ :test => test?,
1443
+ :authorization => authorization,
1444
+ :avs_result => avs_from(avs),
1445
+ :cvv_result => cvv
1446
+ )
1447
+ end
1448
+
1449
+ def avs_from(avs)
1450
+ avs_params = { :code => avs }
1451
+ avs_params.merge!(:message => AVS_CUSTOM_MESSAGES[avs]) if AVS_CUSTOM_MESSAGES.key?(avs)
1452
+ avs_params
1453
+ end
1454
+
1455
+ def parse(action, soap)
1456
+ xml = REXML::Document.new(soap)
1457
+ root = REXML::XPath.first(xml, "//SOAP-ENV:Body")
1458
+ response = root ? parse_element(root[0]) : { :response => soap }
1459
+
1460
+ success, message, authorization, avs, cvv = false, FAILURE_MESSAGE, nil, nil, nil
1461
+
1462
+ fault = (!response) || (response.length < 1) || response.has_key?('faultcode')
1463
+ return [response, success, response['faultstring'], authorization, avs, cvv] if fault
1464
+
1465
+ if response.respond_to?(:[]) && p = response["#{action}_return"]
1466
+ if p.respond_to?(:key?) && p.key?('result_code')
1467
+ success = p['result_code'] == 'A' ? true : false
1468
+ authorization = p['ref_num']
1469
+ avs = AVS_RESULTS[p['avs_result_code']]
1470
+ cvv = p['card_code_result_code']
1471
+ else
1472
+ success = true
1473
+ end
1474
+ message = case action
1475
+ when :get_customer_payment_methods
1476
+ p['item']
1477
+ when :get_transaction_custom
1478
+ items = p['item'].kind_of?(Array) ? p['item'] : [p['item']]
1479
+ items.inject({}) { |hash, item| hash[item['field']] = item['value']; hash }
1480
+ else
1481
+ p
1482
+ end
1483
+ elsif response.respond_to?(:[]) && p = response[:response]
1484
+ message = p # when response is html
1485
+ end
1486
+
1487
+ [response, success, message, authorization, avs, cvv]
1488
+ end
1489
+
1490
+ def parse_element(node)
1491
+ if node.has_elements?
1492
+ response = {}
1493
+ node.elements.each do |e|
1494
+ key = e.name.underscore
1495
+ value = parse_element(e)
1496
+ if response.has_key?(key)
1497
+ if response[key].is_a?(Array)
1498
+ response[key].push(value)
1499
+ else
1500
+ response[key] = [response[key], value]
1501
+ end
1502
+ else
1503
+ response[key] = parse_element(e)
1504
+ end
1505
+ end
1506
+ else
1507
+ response = node.text
1508
+ end
1509
+
1510
+ response
1511
+ end
1512
+
1513
+ end
1514
+ end
1515
+ end
1516
+