start_activemerchant 1.50.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 (218) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1769 -0
  3. data/CONTRIBUTORS +540 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +226 -0
  6. data/lib/active_merchant.rb +67 -0
  7. data/lib/active_merchant/billing.rb +15 -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 +404 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +195 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +291 -0
  18. data/lib/active_merchant/billing/gateways.rb +14 -0
  19. data/lib/active_merchant/billing/gateways/allied_wallet.rb +203 -0
  20. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  21. data/lib/active_merchant/billing/gateways/authorize_net.rb +510 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  24. data/lib/active_merchant/billing/gateways/axcessms.rb +181 -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 +192 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +389 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +58 -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 +211 -0
  37. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  39. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  40. data/lib/active_merchant/billing/gateways/braintree_blue.rb +574 -0
  41. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  42. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  43. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  44. data/lib/active_merchant/billing/gateways/card_stream.rb +238 -0
  45. data/lib/active_merchant/billing/gateways/cashnet.rb +202 -0
  46. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  47. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  48. data/lib/active_merchant/billing/gateways/cenpos.rb +262 -0
  49. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  50. data/lib/active_merchant/billing/gateways/checkout.rb +216 -0
  51. data/lib/active_merchant/billing/gateways/checkout_v2.rb +200 -0
  52. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  53. data/lib/active_merchant/billing/gateways/conekta.rb +210 -0
  54. data/lib/active_merchant/billing/gateways/cyber_source.rb +720 -0
  55. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  56. data/lib/active_merchant/billing/gateways/dibs.rb +206 -0
  57. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  58. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  59. data/lib/active_merchant/billing/gateways/epay.rb +274 -0
  60. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  61. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  62. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  63. data/lib/active_merchant/billing/gateways/eway_rapid.rb +522 -0
  64. data/lib/active_merchant/billing/gateways/exact.rb +227 -0
  65. data/lib/active_merchant/billing/gateways/ezic.rb +206 -0
  66. data/lib/active_merchant/billing/gateways/fat_zebra.rb +213 -0
  67. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  68. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  69. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  70. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  71. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +413 -0
  72. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  73. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  74. data/lib/active_merchant/billing/gateways/garanti.rb +261 -0
  75. data/lib/active_merchant/billing/gateways/global_transport.rb +179 -0
  76. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  77. data/lib/active_merchant/billing/gateways/hps.rb +287 -0
  78. data/lib/active_merchant/billing/gateways/iats_payments.rb +277 -0
  79. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  80. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  81. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  82. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  83. data/lib/active_merchant/billing/gateways/inspire.rb +219 -0
  84. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  85. data/lib/active_merchant/billing/gateways/ipp.rb +175 -0
  86. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  87. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  88. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  89. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  90. data/lib/active_merchant/billing/gateways/litle.rb +345 -0
  91. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  92. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  93. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  94. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  95. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  96. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  97. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  98. data/lib/active_merchant/billing/gateways/mercury.rb +326 -0
  99. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  100. data/lib/active_merchant/billing/gateways/migs.rb +280 -0
  101. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  102. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  103. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  104. data/lib/active_merchant/billing/gateways/monei.rb +307 -0
  105. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  106. data/lib/active_merchant/billing/gateways/moneris_us.rb +298 -0
  107. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  108. data/lib/active_merchant/billing/gateways/nab_transact.rb +290 -0
  109. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  110. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  111. data/lib/active_merchant/billing/gateways/netbilling.rb +224 -0
  112. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  113. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  114. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  115. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  116. data/lib/active_merchant/billing/gateways/omise.rb +319 -0
  117. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  118. data/lib/active_merchant/billing/gateways/optimal_payment.rb +314 -0
  119. data/lib/active_merchant/billing/gateways/orbital.rb +834 -0
  120. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  121. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  122. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  123. data/lib/active_merchant/billing/gateways/pay_conex.rb +246 -0
  124. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +277 -0
  125. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  126. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  127. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  128. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  129. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  130. data/lib/active_merchant/billing/gateways/payflow.rb +308 -0
  131. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +220 -0
  132. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  133. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  134. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  135. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  136. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  137. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  138. data/lib/active_merchant/billing/gateways/paymill.rb +282 -0
  139. data/lib/active_merchant/billing/gateways/paypal.rb +129 -0
  140. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +679 -0
  141. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  142. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  143. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  144. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  145. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  146. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  147. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  148. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  149. data/lib/active_merchant/billing/gateways/payu_in.rb +247 -0
  150. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  151. data/lib/active_merchant/billing/gateways/pin.rb +207 -0
  152. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  153. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  154. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  155. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  156. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  157. data/lib/active_merchant/billing/gateways/quickbooks.rb +280 -0
  158. data/lib/active_merchant/billing/gateways/quickpay.rb +26 -0
  159. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +188 -0
  160. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +240 -0
  161. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +227 -0
  162. data/lib/active_merchant/billing/gateways/qvalent.rb +179 -0
  163. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  164. data/lib/active_merchant/billing/gateways/redsys.rb +406 -0
  165. data/lib/active_merchant/billing/gateways/s5.rb +226 -0
  166. data/lib/active_merchant/billing/gateways/sage.rb +173 -0
  167. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +89 -0
  168. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +115 -0
  169. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  170. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  171. data/lib/active_merchant/billing/gateways/sage_pay.rb +399 -0
  172. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  173. data/lib/active_merchant/billing/gateways/secure_net.rb +263 -0
  174. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  175. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  176. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  177. data/lib/active_merchant/billing/gateways/skip_jack.rb +451 -0
  178. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  179. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  180. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  181. data/lib/active_merchant/billing/gateways/stripe.rb +489 -0
  182. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  183. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  184. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  185. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  186. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  187. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  188. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  189. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  190. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +259 -0
  191. data/lib/active_merchant/billing/gateways/vanco.rb +280 -0
  192. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  193. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  194. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  195. data/lib/active_merchant/billing/gateways/wepay.rb +205 -0
  196. data/lib/active_merchant/billing/gateways/wirecard.rb +420 -0
  197. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  198. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +204 -0
  199. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  200. data/lib/active_merchant/billing/model.rb +30 -0
  201. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +24 -0
  202. data/lib/active_merchant/billing/payment_token.rb +21 -0
  203. data/lib/active_merchant/billing/rails.rb +3 -0
  204. data/lib/active_merchant/billing/response.rb +92 -0
  205. data/lib/active_merchant/connection.rb +172 -0
  206. data/lib/active_merchant/country.rb +332 -0
  207. data/lib/active_merchant/empty.rb +20 -0
  208. data/lib/active_merchant/errors.rb +35 -0
  209. data/lib/active_merchant/network_connection_retries.rb +79 -0
  210. data/lib/active_merchant/post_data.rb +24 -0
  211. data/lib/active_merchant/posts_data.rb +84 -0
  212. data/lib/active_merchant/version.rb +3 -0
  213. data/lib/activemerchant.rb +1 -0
  214. data/lib/certs/cacert.pem +3866 -0
  215. data/lib/support/gateway_support.rb +71 -0
  216. data/lib/support/outbound_hosts.rb +28 -0
  217. data/lib/support/ssl_verify.rb +93 -0
  218. metadata +387 -0
@@ -0,0 +1,281 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class SecurePayAuGateway < Gateway
6
+ API_VERSION = 'xml-4.2'
7
+ PERIODIC_API_VERSION = 'spxml-3.0'
8
+
9
+ class_attribute :test_periodic_url, :live_periodic_url
10
+
11
+ self.test_url = 'https://api.securepay.com.au/test/payment'
12
+ self.live_url = 'https://api.securepay.com.au/xmlapi/payment'
13
+
14
+ self.test_periodic_url = 'https://test.securepay.com.au/xmlapi/periodic'
15
+ self.live_periodic_url = 'https://api.securepay.com.au/xmlapi/periodic'
16
+
17
+ self.supported_countries = ['AU']
18
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
19
+
20
+ # The homepage URL of the gateway
21
+ self.homepage_url = 'http://securepay.com.au'
22
+
23
+ # The name of the gateway
24
+ self.display_name = 'SecurePay'
25
+
26
+ class_attribute :request_timeout
27
+ self.request_timeout = 60
28
+
29
+ self.money_format = :cents
30
+ self.default_currency = 'AUD'
31
+
32
+ # 0 Standard Payment
33
+ # 4 Refund
34
+ # 6 Client Reversal (Void)
35
+ # 10 Preauthorise
36
+ # 11 Preauth Complete (Advice)
37
+ TRANSACTIONS = {
38
+ :purchase => 0,
39
+ :authorization => 10,
40
+ :capture => 11,
41
+ :void => 6,
42
+ :refund => 4
43
+ }
44
+
45
+ PERIODIC_ACTIONS = {
46
+ :add_triggered => "add",
47
+ :remove_triggered => "delete",
48
+ :trigger => "trigger"
49
+ }
50
+
51
+ PERIODIC_TYPES = {
52
+ :add_triggered => 4,
53
+ :remove_triggered => nil,
54
+ :trigger => nil
55
+ }
56
+
57
+ SUCCESS_CODES = [ '00', '08', '11', '16', '77' ]
58
+
59
+ def initialize(options = {})
60
+ requires!(options, :login, :password)
61
+ super
62
+ end
63
+
64
+ def purchase(money, credit_card_or_stored_id, options = {})
65
+ if credit_card_or_stored_id.respond_to?(:number)
66
+ requires!(options, :order_id)
67
+ commit :purchase, build_purchase_request(money, credit_card_or_stored_id, options)
68
+ else
69
+ options[:billing_id] = credit_card_or_stored_id.to_s
70
+ commit_periodic(build_periodic_item(:trigger, money, nil, options))
71
+ end
72
+ end
73
+
74
+ def authorize(money, credit_card, options = {})
75
+ requires!(options, :order_id)
76
+ commit :authorization, build_purchase_request(money, credit_card, options)
77
+ end
78
+
79
+ def capture(money, reference, options = {})
80
+ commit :capture, build_reference_request(money, reference)
81
+ end
82
+
83
+ def refund(money, reference, options = {})
84
+ commit :refund, build_reference_request(money, reference)
85
+ end
86
+
87
+ def credit(money, reference, options = {})
88
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
89
+ refund(money, reference)
90
+ end
91
+
92
+ def void(reference, options = {})
93
+ commit :void, build_reference_request(nil, reference)
94
+ end
95
+
96
+ def store(creditcard, options = {})
97
+ requires!(options, :billing_id, :amount)
98
+ commit_periodic(build_periodic_item(:add_triggered, options[:amount], creditcard, options))
99
+ end
100
+
101
+ def unstore(identification, options = {})
102
+ options[:billing_id] = identification
103
+ commit_periodic(build_periodic_item(:remove_triggered, options[:amount], nil, options))
104
+ end
105
+
106
+ private
107
+
108
+ def build_purchase_request(money, credit_card, options)
109
+ xml = Builder::XmlMarkup.new
110
+
111
+ currency = options[:currency] || currency(money)
112
+
113
+ xml.tag! 'amount', localized_amount(money, currency)
114
+ xml.tag! 'currency', currency
115
+ xml.tag! 'purchaseOrderNo', options[:order_id].to_s.gsub(/[ ']/, '')
116
+
117
+ xml.tag! 'CreditCardInfo' do
118
+ xml.tag! 'cardNumber', credit_card.number
119
+ xml.tag! 'expiryDate', expdate(credit_card)
120
+ xml.tag! 'cvv', credit_card.verification_value if credit_card.verification_value?
121
+ end
122
+
123
+ xml.target!
124
+ end
125
+
126
+ def build_reference_request(money, reference)
127
+ xml = Builder::XmlMarkup.new
128
+
129
+ transaction_id, order_id, preauth_id, original_amount = reference.split('*')
130
+
131
+ xml.tag! 'amount', (money ? amount(money) : original_amount)
132
+ xml.tag! 'currency', options[:currency] || currency(money)
133
+ xml.tag! 'txnID', transaction_id
134
+ xml.tag! 'purchaseOrderNo', order_id
135
+ xml.tag! 'preauthID', preauth_id
136
+
137
+ xml.target!
138
+ end
139
+
140
+ def build_request(action, body)
141
+ xml = Builder::XmlMarkup.new
142
+ xml.instruct!
143
+ xml.tag! 'SecurePayMessage' do
144
+ xml.tag! 'MessageInfo' do
145
+ xml.tag! 'messageID', SecureRandom.hex(15)
146
+ xml.tag! 'messageTimestamp', generate_timestamp
147
+ xml.tag! 'timeoutValue', request_timeout
148
+ xml.tag! 'apiVersion', API_VERSION
149
+ end
150
+
151
+ xml.tag! 'MerchantInfo' do
152
+ xml.tag! 'merchantID', @options[:login]
153
+ xml.tag! 'password', @options[:password]
154
+ end
155
+
156
+ xml.tag! 'RequestType', 'Payment'
157
+ xml.tag! 'Payment' do
158
+ xml.tag! 'TxnList', "count" => 1 do
159
+ xml.tag! 'Txn', "ID" => 1 do
160
+ xml.tag! 'txnType', TRANSACTIONS[action]
161
+ xml.tag! 'txnSource', 23
162
+ xml << body
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ xml.target!
169
+ end
170
+
171
+ def commit(action, request)
172
+ response = parse(ssl_post(test? ? self.test_url : self.live_url, build_request(action, request)))
173
+
174
+ Response.new(success?(response), message_from(response), response,
175
+ :test => test?,
176
+ :authorization => authorization_from(response)
177
+ )
178
+ end
179
+
180
+ def build_periodic_item(action, money, credit_card, options)
181
+ xml = Builder::XmlMarkup.new
182
+
183
+ xml.tag! 'actionType', PERIODIC_ACTIONS[action]
184
+ xml.tag! 'clientID', options[:billing_id].to_s
185
+
186
+ if credit_card
187
+ xml.tag! 'CreditCardInfo' do
188
+ xml.tag! 'cardNumber', credit_card.number
189
+ xml.tag! 'expiryDate', expdate(credit_card)
190
+ xml.tag! 'cvv', credit_card.verification_value if credit_card.verification_value?
191
+ end
192
+ end
193
+ xml.tag! 'amount', amount(money)
194
+ xml.tag! 'periodicType', PERIODIC_TYPES[action] if PERIODIC_TYPES[action]
195
+
196
+ xml.target!
197
+ end
198
+
199
+ def build_periodic_request(body)
200
+ xml = Builder::XmlMarkup.new
201
+ xml.instruct!
202
+ xml.tag! 'SecurePayMessage' do
203
+ xml.tag! 'MessageInfo' do
204
+ xml.tag! 'messageID', SecureRandom.hex(15)
205
+ xml.tag! 'messageTimestamp', generate_timestamp
206
+ xml.tag! 'timeoutValue', request_timeout
207
+ xml.tag! 'apiVersion', PERIODIC_API_VERSION
208
+ end
209
+
210
+ xml.tag! 'MerchantInfo' do
211
+ xml.tag! 'merchantID', @options[:login]
212
+ xml.tag! 'password', @options[:password]
213
+ end
214
+
215
+ xml.tag! 'RequestType', 'Periodic'
216
+ xml.tag! 'Periodic' do
217
+ xml.tag! 'PeriodicList', "count" => 1 do
218
+ xml.tag! 'PeriodicItem', "ID" => 1 do
219
+ xml << body
220
+ end
221
+ end
222
+ end
223
+ end
224
+ xml.target!
225
+ end
226
+
227
+ def commit_periodic(request)
228
+ my_request = build_periodic_request(request)
229
+ #puts my_request
230
+ response = parse(ssl_post(test? ? self.test_periodic_url : self.live_periodic_url, my_request))
231
+
232
+ Response.new(success?(response), message_from(response), response,
233
+ :test => test?,
234
+ :authorization => authorization_from(response)
235
+ )
236
+ end
237
+
238
+ def success?(response)
239
+ SUCCESS_CODES.include?(response[:response_code])
240
+ end
241
+
242
+ def authorization_from(response)
243
+ [response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
244
+ end
245
+
246
+ def message_from(response)
247
+ response[:response_text] || response[:status_description]
248
+ end
249
+
250
+ def expdate(credit_card)
251
+ "#{format(credit_card.month, :two_digits)}/#{format(credit_card.year, :two_digits)}"
252
+ end
253
+
254
+ def parse(body)
255
+ xml = REXML::Document.new(body)
256
+
257
+ response = {}
258
+
259
+ xml.root.elements.to_a.each do |node|
260
+ parse_element(response, node)
261
+ end
262
+
263
+ response
264
+ end
265
+
266
+ def parse_element(response, node)
267
+ if node.has_elements?
268
+ node.elements.each{|element| parse_element(response, element) }
269
+ else
270
+ response[node.name.underscore.to_sym] = node.text
271
+ end
272
+ end
273
+
274
+ # YYYYDDMMHHNNSSKKK000sOOO
275
+ def generate_timestamp
276
+ time = Time.now.utc
277
+ time.strftime("%Y%d%m%H%M%S#{time.usec}+000")
278
+ end
279
+ end
280
+ end
281
+ end
@@ -0,0 +1,105 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class SecurePayTechGateway < Gateway
4
+ class SecurePayTechPostData < PostData
5
+ self.required_fields = [ :OrderReference, :CardNumber, :CardExpiry, :CardHolderName, :CardType, :MerchantID, :MerchantKey, :Amount, :Currency ]
6
+ end
7
+
8
+ self.live_url = self.test_url = 'https://tx.securepaytech.com/web/HttpPostPurchase'
9
+
10
+ PAYMENT_GATEWAY_RESPONSES = {
11
+ 1 => "Transaction OK",
12
+ 2 => "Insufficient funds",
13
+ 3 => "Card expired",
14
+ 4 => "Card declined",
15
+ 5 => "Server error",
16
+ 6 => "Communications error",
17
+ 7 => "Unsupported transaction type",
18
+ 8 => "Bad or malformed request",
19
+ 9 => "Invalid card number"
20
+ }
21
+
22
+ self.default_currency = 'NZD'
23
+ self.supported_countries = ['NZ']
24
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
25
+ self.homepage_url = 'http://www.securepaytech.com/'
26
+ self.display_name = 'SecurePayTech'
27
+
28
+ def initialize(options = {})
29
+ requires!(options, :login, :password)
30
+ super
31
+ end
32
+
33
+ def purchase(money, creditcard, options = {})
34
+ post = SecurePayTechPostData.new
35
+
36
+ add_invoice(post, money, options)
37
+ add_creditcard(post, creditcard)
38
+
39
+ commit(:purchase, post)
40
+ end
41
+
42
+ private
43
+
44
+ def add_invoice(post, money, options)
45
+ post[:Amount] = amount(money)
46
+ post[:Currency] = options[:currency] || currency(money)
47
+
48
+ post[:OrderReference] = options[:order_id]
49
+ end
50
+
51
+ def add_creditcard(post, creditcard)
52
+ post[:CardNumber] = creditcard.number
53
+ post[:CardExpiry] = expdate(creditcard)
54
+ post[:CardHolderName] = creditcard.name
55
+
56
+ if creditcard.verification_value?
57
+ post[:EnableCSC] = true
58
+ post[:CSC] = creditcard.verification_value
59
+ end
60
+
61
+ # SPT will autodetect this
62
+ post[:CardType] = 0
63
+ end
64
+
65
+ def parse(body)
66
+ response = CGI.unescape(body).split(',')
67
+
68
+ result = {}
69
+ result[:result_code] = response[0].to_i
70
+
71
+ if response.length == 2
72
+ result[:fail_reason] = response[1]
73
+ else
74
+ result[:merchant_transaction_reference] = response[1]
75
+ result[:receipt_number] = response[2]
76
+ result[:transaction_number] = response[3]
77
+ result[:authorisation_id] = response[4]
78
+ result[:batch_number] = response[5]
79
+ end
80
+
81
+ result
82
+ end
83
+
84
+ def commit(action, post)
85
+ response = parse( ssl_post(self.live_url, post_data(action, post) ) )
86
+
87
+ Response.new(response[:result_code] == 1, message_from(response), response,
88
+ :test => test?,
89
+ :authorization => response[:merchant_transaction_reference]
90
+ )
91
+ end
92
+
93
+ def message_from(result)
94
+ PAYMENT_GATEWAY_RESPONSES[result[:result_code]]
95
+ end
96
+
97
+ def post_data(action, post)
98
+ post[:MerchantID] = @options[:login]
99
+ post[:MerchantKey] = @options[:password]
100
+ post.to_s
101
+ end
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,451 @@
1
+ #!ruby19
2
+ # encoding: utf-8
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class SkipJackGateway < Gateway
7
+ API_VERSION = '?.?'
8
+
9
+ self.live_url = "https://www.skipjackic.com"
10
+ self.test_url = "https://developer.skipjackic.com"
11
+
12
+ BASIC_PATH = "/scripts/evolvcc.dll"
13
+ ADVANCED_PATH = "/evolvcc/evolvcc.aspx"
14
+
15
+ ACTIONS = {
16
+ :authorization => 'AuthorizeAPI',
17
+ :change_status => 'SJAPI_TransactionChangeStatusRequest',
18
+ :get_status => 'SJAPI_TransactionStatusRequest'
19
+ }
20
+
21
+ SUCCESS_MESSAGE = 'The transaction was successful.'
22
+
23
+ MONETARY_CHANGE_STATUSES = ['SETTLE', 'AUTHORIZE', 'AUTHORIZE ADDITIONAL', 'CREDIT', 'SPLITSETTLE']
24
+
25
+ CARD_CODE_ERRORS = %w( N S "" )
26
+
27
+ CARD_CODE_MESSAGES = {
28
+ "M" => "Card verification number matched",
29
+ "N" => "Card verification number didn't match",
30
+ "P" => "Card verification number was not processed",
31
+ "S" => "Card verification number should be on card but was not indicated",
32
+ "U" => "Issuer was not certified for card verification",
33
+ "" => "Transaction failed because incorrect card verification number was entered or no number was entered"
34
+ }
35
+
36
+ AVS_ERRORS = %w( A B C E I N O P R W Z )
37
+
38
+ AVS_MESSAGES = {
39
+ "A" => "Street address matches billing information, zip/postal code does not",
40
+ "B" => "Street address match for international transaction. Postal code not verified due to incompatible formats",
41
+ "C" => "Street address and postal code not verified for internation transaction due to incompatible formats",
42
+ "D" => "Street address and postal code match for international transaction",
43
+ "E" => "Address verification service error",
44
+ "I" => "Address information not verified by international issuer",
45
+ "M" => "Street address and postal code match for international transaction",
46
+ "N" => "Neither street address nor zip/postal match billing information",
47
+ "O" => "Non-US issuer does not participate",
48
+ "P" => "Postal codes match for international transaction but street address not verified due to incompatible formats",
49
+ "R" => "Payment gateway was unavailable or timed out",
50
+ "S" => "Address verification service not supported by issuer",
51
+ "U" => "Address information is unavailable",
52
+ "W" => "9-digit zip/postal code matches billing information, street address does not",
53
+ "X" => "Street address and 9-digit zip/postal code matches billing information",
54
+ "Y" => "Street address and 5-digit zip/postal code matches billing information",
55
+ "Z" => "5-digit zip/postal code matches billing information, street address does not",
56
+ }
57
+
58
+ CHANGE_STATUS_ERROR_MESSAGES = {
59
+ '0' => 'Success',
60
+ '-1' => 'Invalid Command',
61
+ '-2' => 'Parameter Missing',
62
+ '-3' => 'Failed retrieving response',
63
+ '-4' => 'Invalid Status',
64
+ '-5' => 'Failed reading security flags',
65
+ '-6' => 'Developer serial number not found',
66
+ '-7' => 'Invalid Serial Number'
67
+ }
68
+
69
+ TRANSACTION_CURRENT_STATUS = {
70
+ '0' => 'Idle',
71
+ '1' => 'Authorized',
72
+ '2' => 'Denied',
73
+ '3' => 'Settled',
74
+ '4' => 'Credited',
75
+ '5' => 'Deleted',
76
+ '6' => 'Archived',
77
+ '7' => 'Pre-Authorized',
78
+ '8' => 'Split Settled'
79
+ }
80
+
81
+ TRANSACTION_PENDING_STATUS = {
82
+ '0' => 'Idle',
83
+ '1' => 'Pending Credit',
84
+ '2' => 'Pending Settlement',
85
+ '3' => 'Pending Authorization',
86
+ '4' => 'Pending Manual Settlement',
87
+ '5' => 'Pending Recurring'
88
+ }
89
+
90
+ RETURN_CODE_MESSAGES = {
91
+ '-1' => 'Data was not by received intact by Skipjack Transaction Network.',
92
+ '0' => 'Communication Failure. Error in Request and Response at IP level.',
93
+ '1' => 'Valid Data. Authorization request was valid.',
94
+ '-35' => 'Invalid credit card number. Retry with correct credit card number.',
95
+ '-37' => 'Merchant Processor Unavailable. Skipjack is unable to communicate with payment Processor. Retry',
96
+ '-39' => 'Length or value of HTML Serial. Number Invalid serial number. Check HTML Serial Number length and that it is a correct/valid number. Confirm you are sending to the correct environment (Development or Production)',
97
+ '-51' => 'The value or length for billing zip code is incorrect.',
98
+ '-52' => 'The value or length for shipping zip code is incorrect.',
99
+ '-53' => 'The value or length for credit card expiration month is incorrect.',
100
+ '-54' => 'The value or length of the month or year of the credit card account number was incorrect.',
101
+ '-55' => 'The value or length or billing street address is incorrect.',
102
+ '-56' => 'The value or length of the shipping address is incorrect.',
103
+ '-57' => 'The length of the transaction amount must be at least 3 digits long (excluding the decimal place).',
104
+ '-58' => 'Length or value in Merchant Name Merchant Name associated with Skipjack account is misconfigured or invalid',
105
+ '-59' => 'Length or value in Merchant Address Merchant Address associated with Skipjack account is misconfigured or invalid',
106
+ '-60' => 'Length or value in Merchant State Merchant State associated with Skipjack account is misconfigured or invalid',
107
+ '-61' => 'The value or length for shipping state/province is empty.',
108
+ '-62' => 'The value for length orderstring is empty.',
109
+ '-64' => 'The value for the phone number is incorrect.',
110
+ '-65' => 'The value or length for billing name is empty.',
111
+ '-66' => 'The value or length for billing e-mail is empty.',
112
+ '-67' => 'The value or length for billing street address is empty.',
113
+ '-68' => 'The value or length for billing city is empty.',
114
+ '-69' => 'The value or length for billing state is empty.',
115
+ '-70' => 'Empty zipcode Zip Code field is empty.',
116
+ '-71' => 'Empty ordernumber Ordernumber field is empty.',
117
+ '-72' => 'Empty accountnumber Accountnumber field is empty',
118
+ '-73' => 'Empty month Month field is empty.',
119
+ '-74' => 'Empty year Year field is empty.',
120
+ '-75' => 'Empty serialnumber Serialnumber field is empty.',
121
+ '-76' => 'Empty transactionamount Transaction amount field is empty.',
122
+ '-77' => 'Empty orderstring Orderstring field is empty.',
123
+ '-78' => 'Empty shiptophone Shiptophone field is empty.',
124
+ '-79' => 'The value or length for billing name is empty.',
125
+ '-80' => 'Length shipto name Error in the length or value of shiptophone.',
126
+ '-81' => 'Length or value of Customer location',
127
+ '-82' => 'The value or length for billing state is empty.',
128
+ '-83' => 'The value or length for shipping phone is empty.',
129
+ '-84' => 'There is already an existing pending transaction in the register sharing the posted Order Number.',
130
+ '-85' => 'Airline leg info invalid Airline leg field value is invalid or empty.',
131
+ '-86' => 'Airline ticket info invalid Airline ticket info field is invalid or empty',
132
+ '-87' => 'Point of Sale check routing number must be 9 numeric digits Point of Sale check routing number is invalid or empty.',
133
+ '-88' => 'Point of Sale check account number missing or invalid Point of Sale check account number is invalid or empty.',
134
+ '-89' => 'Point of Sale check MICR missing or invalid Point of Sale check MICR invalid or empty.',
135
+ '-90' => 'Point of Sale check number missing or invalid Point of Sale check number invalid or empty.',
136
+ '-91' => 'CVV2 Invalid or empty "Make CVV a required field feature" enabled (New feature 01 April 2006) in the Merchant Account Setup interface but no CVV code was sent in the transaction data.',
137
+ '-92' => 'Approval Code Invalid Approval Code Invalid. Approval Code is a 6 digit code.',
138
+ '-93' => 'Blind Credits Request Refused "Allow Blind Credits" option must be enabled on the Skipjack Merchant Account.',
139
+ '-94' => 'Blind Credits Failed',
140
+ '-95' => 'Voice Authorization Request Refused Voice Authorization option must be enabled on the Skipjack Merchant Account.',
141
+ '-96' => 'Voice Authorizations Failed',
142
+ '-97' => 'Fraud Rejection Violates Velocity Settling.',
143
+ '-98' => 'Invalid Discount Amount',
144
+ '-99' => 'POS PIN Debit Pin Block Debit-specific',
145
+ '-100' => 'POS PIN Debit Invalid Key Serial Number Debit-specific',
146
+ '-101' => 'Invalid Authentication Data Data for Verified by Visa/MC Secure Code is invalid.',
147
+ '-102' => 'Authentication Data Not Allowed',
148
+ '-103' => 'POS Check Invalid Birth Date POS check dateofbirth variable contains a birth date in an incorrect format. Use MM/DD/YYYY format for this variable.',
149
+ '-104' => 'POS Check Invalid Identification Type POS check identificationtype variable contains a identification type value which is invalid. Use the single digit value where Social Security Number=1, Drivers License=2 for this variable.',
150
+ '-105' => 'Invalid trackdata Track Data is in invalid format.',
151
+ '-106' => 'POS Check Invalid Account Type',
152
+ '-107' => 'POS PIN Debit Invalid Sequence Number',
153
+ '-108' => 'Invalid Transaction ID',
154
+ '-109' => 'Invalid From Account Type',
155
+ '-110' => 'Pos Error Invalid To Account Type',
156
+ '-112' => 'Pos Error Invalid Auth Option',
157
+ '-113' => 'Pos Error Transaction Failed',
158
+ '-114' => 'Pos Error Invalid Incoming Eci',
159
+ '-115' => 'POS Check Invalid Check Type',
160
+ '-116' => 'POS Check Invalid Lane Number POS Check lane or cash register number is invalid. Use a valid lane or cash register number that has been configured in the Skipjack Merchant Account.',
161
+ '-117' => 'POS Check Invalid Cashier Number'
162
+ }
163
+
164
+ self.supported_countries = ['US', 'CA']
165
+ self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :discover, :diners_club]
166
+ self.homepage_url = 'http://www.skipjack.com/'
167
+ self.display_name = 'SkipJack'
168
+
169
+ # Creates a new SkipJackGateway
170
+ #
171
+ # The gateway requires that a valid login and password be passed
172
+ # in the +options+ hash.
173
+ #
174
+ # ==== Options
175
+ #
176
+ # * <tt>:login</tt> -- The SkipJack Merchant Serial Number.
177
+ # * <tt>:password</tt> -- The SkipJack Developer Serial Number.
178
+ # * <tt>:test => +true+ or +false+</tt> -- Use the test or live SkipJack url.
179
+ # * <tt>:advanced => +true+ or +false+</tt> -- Set to true if you're using an advanced processor
180
+ # See the SkipJack Integration Guide for details. (default: +false+)
181
+ def initialize(options = {})
182
+ requires!(options, :login, :password)
183
+ super
184
+ end
185
+
186
+ def authorize(money, creditcard, options = {})
187
+ requires!(options, :order_id, :email)
188
+ post = {}
189
+ add_invoice(post, options)
190
+ add_creditcard(post, creditcard)
191
+ add_address(post, options)
192
+ add_customer_data(post, options)
193
+ commit(:authorization, money, post)
194
+ end
195
+
196
+ def purchase(money, creditcard, options = {})
197
+ authorization = authorize(money, creditcard, options)
198
+ if authorization.success?
199
+ capture(money, authorization.authorization)
200
+ else
201
+ authorization
202
+ end
203
+ end
204
+
205
+ # Captures the funds from an authorized transaction.
206
+ #
207
+ # ==== Parameters
208
+ #
209
+ # * <tt>money</tt> -- The amount to be capture as an Integer in cents.
210
+ # * <tt>authorization</tt> -- The authorization returned from the previous authorize request.
211
+ # * <tt>options</tt> -- A hash of optional parameters.
212
+ #
213
+ # ==== Options
214
+ #
215
+ # * <tt>:force_settlement</tt> -- Force the settlement to occur as soon as possible. This option is not supported by other gateways. See the SkipJack API reference for more details
216
+ def capture(money, authorization, options = {})
217
+ post = { }
218
+ add_status_action(post, 'SETTLE')
219
+ add_forced_settlement(post, options)
220
+ add_transaction_id(post, authorization)
221
+ commit(:change_status, money, post)
222
+ end
223
+
224
+ def void(authorization, options = {})
225
+ post = {}
226
+ add_status_action(post, 'DELETE')
227
+ add_forced_settlement(post, options)
228
+ add_transaction_id(post, authorization)
229
+ commit(:change_status, nil, post)
230
+ end
231
+
232
+ def refund(money, identification, options = {})
233
+ post = {}
234
+ add_status_action(post, 'CREDIT')
235
+ add_forced_settlement(post, options)
236
+ add_transaction_id(post, identification)
237
+ commit(:change_status, money, post)
238
+ end
239
+
240
+ def credit(money, identification, options = {})
241
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
242
+ refund(money, identification, options)
243
+ end
244
+
245
+ def status(order_id)
246
+ commit(:get_status, nil, :szOrderNumber => order_id)
247
+ end
248
+
249
+ private
250
+
251
+ def advanced?
252
+ @options[:advanced]
253
+ end
254
+
255
+ def add_forced_settlement(post, options)
256
+ post[:szForceSettlement] = options[:force_settlment] ? 1 : 0
257
+ end
258
+
259
+ def add_status_action(post, action)
260
+ post[:szDesiredStatus] = action
261
+ end
262
+
263
+ def commit(action, money, parameters)
264
+ response = parse( ssl_post( url_for(action), post_data(action, money, parameters) ), action )
265
+
266
+ # Pass along the original transaction id in the case an update transaction
267
+ Response.new(response[:success], message_from(response, action), response,
268
+ :test => test?,
269
+ :authorization => response[:szTransactionFileName] || parameters[:szTransactionId],
270
+ :avs_result => { :code => response[:szAVSResponseCode] },
271
+ :cvv_result => response[:szCVV2ResponseCode]
272
+ )
273
+ end
274
+
275
+ def url_for(action)
276
+ result = test? ? self.test_url : self.live_url
277
+ result += advanced? && action == :authorization ? ADVANCED_PATH : BASIC_PATH
278
+ result += "?#{ACTIONS[action]}"
279
+ end
280
+
281
+ def add_credentials(params, action)
282
+ if action == :authorization
283
+ params[:SerialNumber] = @options[:login]
284
+ params[:DeveloperSerialNumber] = @options[:password]
285
+ else
286
+ params[:szSerialNumber] = @options[:login]
287
+ params[:szDeveloperSerialNumber] = @options[:password]
288
+ end
289
+ end
290
+
291
+ def add_amount(params, action, money)
292
+ if action == :authorization
293
+ params[:TransactionAmount] = amount(money)
294
+ else
295
+ params[:szAmount] = amount(money) if MONETARY_CHANGE_STATUSES.include?(params[:szDesiredStatus])
296
+ end
297
+ end
298
+
299
+ def parse(body, action)
300
+ case action
301
+ when :authorization
302
+ parse_authorization_response(body)
303
+ when :get_status
304
+ parse_status_response(body, [ :SerialNumber, :TransactionAmount, :TransactionStatusCode, :TransactionStatusMessage, :OrderNumber, :TransactionDateTime, :TransactionID, :ApprovalCode, :BatchNumber ])
305
+ else
306
+ parse_status_response(body, [ :SerialNumber, :TransactionAmount, :DesiredStatus, :StatusResponse, :StatusResponseMessage, :OrderNumber, :AuditID ])
307
+ end
308
+ end
309
+
310
+ def split_lines(body)
311
+ body.split(/[\r\n]+/)
312
+ end
313
+
314
+ def split_line(line)
315
+ line.split(/","/).collect { |key| key.sub(/"*([^"]*)"*/, '\1').strip; }
316
+ end
317
+
318
+ def authorize_response_map(body)
319
+ lines = split_lines(body)
320
+ keys, values = split_line(lines[0]), split_line(lines[1])
321
+ Hash[*(keys.zip(values).flatten)].symbolize_keys
322
+ end
323
+
324
+ def parse_authorization_response(body)
325
+ result = authorize_response_map(body)
326
+ result[:success] = (result[:szIsApproved] == '1')
327
+ result
328
+ end
329
+
330
+ def parse_status_response(body, response_keys)
331
+ lines = split_lines(body)
332
+
333
+ keys = [ :szSerialNumber, :szErrorCode, :szNumberRecords]
334
+ values = split_line(lines[0])[0..2]
335
+
336
+ result = Hash[*(keys.zip(values).flatten)]
337
+
338
+ result[:szErrorMessage] = ''
339
+ result[:success] = (result[:szErrorCode] == '0')
340
+
341
+ if result[:success]
342
+ lines[1..-1].each do |line|
343
+ values = split_line(line)
344
+ response_keys.each_with_index do |key, index|
345
+ result[key] = values[index]
346
+ end
347
+ end
348
+ else
349
+ result[:szErrorMessage] = lines[1]
350
+ end
351
+ result
352
+ end
353
+
354
+ def post_data(action, money, params = {})
355
+ add_credentials(params, action)
356
+ add_amount(params, action, money)
357
+ sorted_params = params.to_a.sort{|a,b| a.to_s <=> b.to_s}.reverse
358
+ sorted_params.collect { |key, value| "#{key.to_s}=#{CGI.escape(value.to_s)}" }.join("&")
359
+ end
360
+
361
+ def add_transaction_id(post, transaction_id)
362
+ post[:szTransactionId] = transaction_id
363
+ end
364
+
365
+ def add_invoice(post, options)
366
+ post[:OrderNumber] = sanitize_order_id(options[:order_id])
367
+ post[:CustomerCode] = options[:customer].to_s.slice(0, 17)
368
+ post[:InvoiceNumber] = options[:invoice]
369
+ post[:OrderDescription] = options[:description]
370
+
371
+ if order_items = options[:items]
372
+ post[:OrderString] = order_items.collect { |item| "#{item[:sku]}~#{item[:description].tr('~','-')}~#{item[:declared_value]}~#{item[:quantity]}~#{item[:taxable]}~~~~~~~~#{item[:tax_rate]}~||"}.join
373
+ else
374
+ post[:OrderString] = '1~None~0.00~0~N~||'
375
+ end
376
+ end
377
+
378
+ def add_creditcard(post, creditcard)
379
+ post[:AccountNumber] = creditcard.number
380
+ post[:Month] = creditcard.month
381
+ post[:Year] = creditcard.year
382
+ post[:CVV2] = creditcard.verification_value if creditcard.verification_value?
383
+ post[:SJName] = creditcard.name
384
+ end
385
+
386
+ def add_customer_data(post, options)
387
+ post[:Email] = options[:email]
388
+ end
389
+
390
+ def add_address(post, options)
391
+ if address = options[:billing_address] || options[:address]
392
+ post[:StreetAddress] = address[:address1]
393
+ post[:StreetAddress2] = address[:address2]
394
+ post[:City] = address[:city]
395
+ post[:State] = address[:state] || 'XX'
396
+ post[:ZipCode] = address[:zip]
397
+ post[:Country] = address[:country]
398
+ post[:Phone] = address[:phone]
399
+ post[:Fax] = address[:fax]
400
+ end
401
+
402
+ if address = options[:shipping_address]
403
+ post[:ShipToName] = address[:name]
404
+ post[:ShipToStreetAddress] = address[:address1]
405
+ post[:ShipToStreetAddress2] = address[:address2]
406
+ post[:ShipToCity] = address[:city]
407
+ post[:ShipToState] = address[:state] || 'XX'
408
+ post[:ShipToZipCode] = address[:zip]
409
+ post[:ShipToCountry] = address[:country]
410
+ post[:ShipToPhone] = address[:phone]
411
+ post[:ShipToFax] = address[:fax]
412
+ end
413
+
414
+ # The phone number for the shipping address is required
415
+ # Use the billing address phone number if a shipping address
416
+ # phone number wasn't provided
417
+ post[:ShipToPhone] = post[:Phone] if post[:ShipToPhone].blank?
418
+ end
419
+
420
+ def message_from(response, action)
421
+ case action
422
+ when :authorization
423
+ message_from_authorization(response)
424
+ when :get_status
425
+ message_from_status(response)
426
+ else
427
+ message_from_status(response)
428
+ end
429
+ end
430
+
431
+ def message_from_authorization(response)
432
+ if response[:success]
433
+ return SUCCESS_MESSAGE
434
+ else
435
+ return CARD_CODE_MESSAGES[response[:szCVV2ResponseCode]] if CARD_CODE_ERRORS.include?(response[:szCVV2ResponseCode])
436
+ return AVS_MESSAGES[response[:szAVSResponseMessage]] if AVS_ERRORS.include?(response[:szAVSResponseCode])
437
+ return RETURN_CODE_MESSAGES[response[:szReturnCode]] if response[:szReturnCode] != '1'
438
+ return response[:szAuthorizationDeclinedMessage]
439
+ end
440
+ end
441
+
442
+ def message_from_status(response)
443
+ response[:success] ? SUCCESS_MESSAGE : response[:szErrorMessage]
444
+ end
445
+
446
+ def sanitize_order_id(value)
447
+ value.to_s.gsub(/[^\w.]/, '')
448
+ end
449
+ end
450
+ end
451
+ end