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,97 @@
1
+ require 'active_merchant/billing/gateways/sage/sage_core'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class SageVirtualCheckGateway < Gateway #:nodoc:
6
+ include SageCore
7
+ self.live_url = 'https://www.sagepayments.net/cgi-bin/eftVirtualCheck.dll?transaction'
8
+ self.source = 'virtual_check'
9
+
10
+ def purchase(money, credit_card, options = {})
11
+ post = {}
12
+ add_check(post, credit_card)
13
+ add_check_customer_data(post, options)
14
+ add_transaction_data(post, money, options)
15
+ commit(:purchase, post)
16
+ end
17
+
18
+ def void(reference, options = {})
19
+ post = {}
20
+ add_reference(post, reference)
21
+ commit(:void, post)
22
+ end
23
+
24
+ def credit(money, credit_card, options = {})
25
+ post = {}
26
+ add_check(post, credit_card)
27
+ add_check_customer_data(post, options)
28
+ add_transaction_data(post, money, options)
29
+ commit(:credit, post)
30
+ end
31
+
32
+ private
33
+ def add_check(post, check)
34
+ post[:C_first_name] = check.first_name
35
+ post[:C_last_name] = check.last_name
36
+ post[:C_rte] = check.routing_number
37
+ post[:C_acct] = check.account_number
38
+ post[:C_check_number] = check.number
39
+ post[:C_acct_type] = account_type(check)
40
+ end
41
+
42
+ def add_check_customer_data(post, options)
43
+ # Required  Customer Type – (NACHA Transaction Class)
44
+ # CCD for Commercial, Merchant Initiated
45
+ # PPD for Personal, Merchant Initiated
46
+ # WEB for Internet, Consumer Initiated
47
+ # RCK for Returned Checks
48
+ # ARC for Account Receivable Entry
49
+ # TEL for TelephoneInitiated
50
+ post[:C_customer_type] = "WEB"
51
+
52
+ # Optional  10  Digit Originator  ID – Assigned  By for  each transaction  class  or  business  purpose. If  not provided, the default Originator ID for the specific  Customer Type will be applied. 
53
+ post[:C_originator_id] = options[:originator_id]
54
+
55
+ # Optional  Transaction Addenda
56
+ post[:T_addenda] = options[:addenda]
57
+
58
+ # Required  Check  Writer  Social  Security  Number  (  Numbers Only, No Dashes ) 
59
+ post[:C_ssn] = options[:ssn].to_s.gsub(/[^\d]/, '')
60
+
61
+ post[:C_dl_state_code] = options[:drivers_license_state]
62
+ post[:C_dl_number] = options[:drivers_license_number]
63
+ post[:C_dob] = format_birth_date(options[:date_of_birth])
64
+ end
65
+
66
+ def format_birth_date(date)
67
+ date.respond_to?(:strftime) ? date.strftime("%m/%d/%Y") : date
68
+ end
69
+
70
+ # DDA for Checking
71
+ # SAV for Savings 
72
+ def account_type(check)
73
+ case check.account_type
74
+ when 'checking' then 'DDA'
75
+ when 'savings' then 'SAV'
76
+ else raise ArgumentError, "Unknown account type #{check.account_type}"
77
+ end
78
+ end
79
+
80
+ def parse(data)
81
+ response = {}
82
+ response[:success] = data[1,1]
83
+ response[:code] = data[2,6].strip
84
+ response[:message] = data[8,32].strip
85
+ response[:risk] = data[40, 2]
86
+ response[:reference] = data[42, 10]
87
+
88
+ extra_data = data[53...-1].split("\034")
89
+ response[:order_number] = extra_data[0]
90
+ response[:authentication_indicator] = extra_data[1]
91
+ response[:authentication_disclosure] = extra_data[2]
92
+ response
93
+ end
94
+ end
95
+ end
96
+ end
97
+
@@ -0,0 +1,399 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class SagePayGateway < Gateway
4
+ cattr_accessor :simulate
5
+ self.simulate = false
6
+
7
+ class_attribute :simulator_url
8
+
9
+ self.test_url = 'https://test.sagepay.com/gateway/service'
10
+ self.live_url = 'https://live.sagepay.com/gateway/service'
11
+ self.simulator_url = 'https://test.sagepay.com/Simulator'
12
+
13
+ APPROVED = 'OK'
14
+
15
+ TRANSACTIONS = {
16
+ :purchase => 'PAYMENT',
17
+ :credit => 'REFUND',
18
+ :authorization => 'DEFERRED',
19
+ :capture => 'RELEASE',
20
+ :void => 'VOID',
21
+ :abort => 'ABORT',
22
+ :store => 'TOKEN',
23
+ :unstore => 'REMOVETOKEN'
24
+ }
25
+
26
+ CREDIT_CARDS = {
27
+ :visa => "VISA",
28
+ :master => "MC",
29
+ :delta => "DELTA",
30
+ :solo => "SOLO",
31
+ :switch => "MAESTRO",
32
+ :maestro => "MAESTRO",
33
+ :american_express => "AMEX",
34
+ :electron => "UKE",
35
+ :diners_club => "DC",
36
+ :jcb => "JCB"
37
+ }
38
+
39
+ ELECTRON = /^(424519|42496[23]|450875|48440[6-8]|4844[1-5][1-5]|4917[3-5][0-9]|491880)\d{10}(\d{3})?$/
40
+
41
+ AVS_CVV_CODE = {
42
+ "NOTPROVIDED" => nil,
43
+ "NOTCHECKED" => 'X',
44
+ "MATCHED" => 'Y',
45
+ "NOTMATCHED" => 'N'
46
+ }
47
+
48
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :switch, :solo, :maestro, :diners_club]
49
+ self.supported_countries = ['GB', 'IE']
50
+ self.default_currency = 'GBP'
51
+
52
+ self.homepage_url = 'http://www.sagepay.com'
53
+ self.display_name = 'SagePay'
54
+
55
+ def initialize(options = {})
56
+ requires!(options, :login)
57
+ super
58
+ end
59
+
60
+ def purchase(money, payment_method, options = {})
61
+ requires!(options, :order_id)
62
+
63
+ post = {}
64
+
65
+ add_amount(post, money, options)
66
+ add_invoice(post, options)
67
+ add_payment_method(post, payment_method, options)
68
+ add_address(post, options)
69
+ add_customer_data(post, options)
70
+ add_optional_data(post, options)
71
+
72
+ commit(:purchase, post)
73
+ end
74
+
75
+ def authorize(money, payment_method, options = {})
76
+ requires!(options, :order_id)
77
+
78
+ post = {}
79
+
80
+ add_amount(post, money, options)
81
+ add_invoice(post, options)
82
+ add_payment_method(post, payment_method, options)
83
+ add_address(post, options)
84
+ add_customer_data(post, options)
85
+ add_optional_data(post, options)
86
+
87
+ commit(:authorization, post)
88
+ end
89
+
90
+ # You can only capture a transaction once, even if you didn't capture the full amount the first time.
91
+ def capture(money, identification, options = {})
92
+ post = {}
93
+
94
+ add_reference(post, identification)
95
+ add_release_amount(post, money, options)
96
+
97
+ commit(:capture, post)
98
+ end
99
+
100
+ def void(identification, options = {})
101
+ post = {}
102
+
103
+ add_reference(post, identification)
104
+ action = abort_or_void_from(identification)
105
+
106
+ commit(action, post)
107
+ end
108
+
109
+ # Refunding requires a new order_id to passed in, as well as a description
110
+ def refund(money, identification, options = {})
111
+ requires!(options, :order_id, :description)
112
+
113
+ post = {}
114
+
115
+ add_credit_reference(post, identification)
116
+ add_amount(post, money, options)
117
+ add_invoice(post, options)
118
+
119
+ commit(:credit, post)
120
+ end
121
+
122
+ def credit(money, identification, options = {})
123
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
124
+ refund(money, identification, options)
125
+ end
126
+
127
+ def store(credit_card, options = {})
128
+ post = {}
129
+ add_credit_card(post, credit_card)
130
+ add_currency(post, 0, options)
131
+
132
+ commit(:store, post)
133
+ end
134
+
135
+ def unstore(token, options = {})
136
+ post = {}
137
+ add_token(post, token)
138
+ commit(:unstore, post)
139
+ end
140
+
141
+ def verify(credit_card, options={})
142
+ MultiResponse.run(:use_first_response) do |r|
143
+ r.process { authorize(100, credit_card, options) }
144
+ r.process(:ignore_result) { void(r.authorization, options) }
145
+ end
146
+ end
147
+
148
+ private
149
+ def add_reference(post, identification)
150
+ order_id, transaction_id, authorization, security_key = identification.split(';')
151
+
152
+ add_pair(post, :VendorTxCode, order_id)
153
+ add_pair(post, :VPSTxId, transaction_id)
154
+ add_pair(post, :TxAuthNo, authorization)
155
+ add_pair(post, :SecurityKey, security_key)
156
+ end
157
+
158
+ def add_credit_reference(post, identification)
159
+ order_id, transaction_id, authorization, security_key = identification.split(';')
160
+
161
+ add_pair(post, :RelatedVendorTxCode, order_id)
162
+ add_pair(post, :RelatedVPSTxId, transaction_id)
163
+ add_pair(post, :RelatedTxAuthNo, authorization)
164
+ add_pair(post, :RelatedSecurityKey, security_key)
165
+ end
166
+
167
+ def add_amount(post, money, options)
168
+ currency = options[:currency] || currency(money)
169
+ add_pair(post, :Amount, localized_amount(money, currency), :required => true)
170
+ add_pair(post, :Currency, currency, :required => true)
171
+ end
172
+
173
+ def add_currency(post, money, options)
174
+ currency = options[:currency] || currency(money)
175
+ add_pair(post, :Currency, currency, :required => true)
176
+ end
177
+
178
+ # doesn't actually use the currency -- dodgy!
179
+ def add_release_amount(post, money, options)
180
+ add_pair(post, :ReleaseAmount, amount(money), :required => true)
181
+ end
182
+
183
+ def add_customer_data(post, options)
184
+ add_pair(post, :CustomerEMail, truncate(options[:email], 255)) unless options[:email].blank?
185
+ add_pair(post, :ClientIPAddress, options[:ip])
186
+ end
187
+
188
+ def add_optional_data(post, options)
189
+ add_pair(post, :GiftAidPayment, options[:gift_aid_payment]) unless options[:gift_aid_payment].blank?
190
+ add_pair(post, :Apply3DSecure, options[:apply_3d_secure]) unless options[:apply_3d_secure].blank?
191
+ add_pair(post, :CreateToken, 1) unless options[:store].blank?
192
+ add_pair(post, :FIRecipientAcctNumber, options[:recipient_account_number])
193
+ add_pair(post, :FIRecipientSurname, options[:recipient_surname])
194
+ add_pair(post, :FIRecipientPostcode, options[:recipient_postcode])
195
+ add_pair(post, :FIRecipientDoB, options[:recipient_dob])
196
+ end
197
+
198
+ def add_address(post, options)
199
+ if billing_address = options[:billing_address] || options[:address]
200
+ first_name, last_name = parse_first_and_last_name(billing_address[:name])
201
+ add_pair(post, :BillingSurname, last_name)
202
+ add_pair(post, :BillingFirstnames, first_name)
203
+ add_pair(post, :BillingAddress1, truncate(billing_address[:address1], 100))
204
+ add_pair(post, :BillingAddress2, truncate(billing_address[:address2], 100))
205
+ add_pair(post, :BillingCity, truncate(billing_address[:city], 40))
206
+ add_pair(post, :BillingState, truncate(billing_address[:state], 2)) if is_usa(billing_address[:country])
207
+ add_pair(post, :BillingCountry, truncate(billing_address[:country], 2))
208
+ add_pair(post, :BillingPhone, sanitize_phone(billing_address[:phone]))
209
+ add_pair(post, :BillingPostCode, truncate(billing_address[:zip], 10))
210
+ end
211
+
212
+ if shipping_address = options[:shipping_address] || billing_address
213
+ first_name, last_name = parse_first_and_last_name(shipping_address[:name])
214
+ add_pair(post, :DeliverySurname, last_name)
215
+ add_pair(post, :DeliveryFirstnames, first_name)
216
+ add_pair(post, :DeliveryAddress1, truncate(shipping_address[:address1], 100))
217
+ add_pair(post, :DeliveryAddress2, truncate(shipping_address[:address2], 100))
218
+ add_pair(post, :DeliveryCity, truncate(shipping_address[:city], 40))
219
+ add_pair(post, :DeliveryState, truncate(shipping_address[:state], 2)) if is_usa(shipping_address[:country])
220
+ add_pair(post, :DeliveryCountry, truncate(shipping_address[:country], 2))
221
+ add_pair(post, :DeliveryPhone, sanitize_phone(shipping_address[:phone]))
222
+ add_pair(post, :DeliveryPostCode, truncate(shipping_address[:zip], 10))
223
+ end
224
+ end
225
+
226
+ def add_invoice(post, options)
227
+ add_pair(post, :VendorTxCode, sanitize_order_id(options[:order_id]), :required => true)
228
+ add_pair(post, :Description, truncate(options[:description] || options[:order_id], 100))
229
+ end
230
+
231
+ def add_payment_method(post, payment_method, options)
232
+ if payment_method.respond_to?(:number)
233
+ add_credit_card(post, payment_method)
234
+ else
235
+ add_token_details(post, payment_method, options)
236
+ end
237
+ end
238
+
239
+ def add_credit_card(post, credit_card)
240
+ add_pair(post, :CardHolder, truncate(credit_card.name, 50), :required => true)
241
+ add_pair(post, :CardNumber, credit_card.number, :required => true)
242
+
243
+ add_pair(post, :ExpiryDate, format_date(credit_card.month, credit_card.year), :required => true)
244
+
245
+ if requires_start_date_or_issue_number?(credit_card)
246
+ add_pair(post, :StartDate, format_date(credit_card.start_month, credit_card.start_year))
247
+ add_pair(post, :IssueNumber, credit_card.issue_number)
248
+ end
249
+ add_pair(post, :CardType, map_card_type(credit_card))
250
+
251
+ add_pair(post, :CV2, credit_card.verification_value)
252
+ end
253
+
254
+ def add_token_details(post, token, options)
255
+ add_token(post, token)
256
+ add_pair(post, :StoreToken, options[:customer])
257
+ end
258
+
259
+ def add_token(post, token)
260
+ add_pair(post, :Token, token)
261
+ end
262
+
263
+ def sanitize_order_id(order_id)
264
+ cleansed = order_id.to_s.gsub(/[^-a-zA-Z0-9._]/, '')
265
+ truncate(cleansed, 40)
266
+ end
267
+
268
+ def sanitize_phone(phone)
269
+ return nil unless phone
270
+ cleansed = phone.to_s.gsub(/[^0-9+]/, '')
271
+ truncate(cleansed, 20)
272
+ end
273
+
274
+ def is_usa(country)
275
+ truncate(country, 2) == 'US'
276
+ end
277
+
278
+ def map_card_type(credit_card)
279
+ raise ArgumentError, "The credit card type must be provided" if card_brand(credit_card).blank?
280
+
281
+ card_type = card_brand(credit_card).to_sym
282
+
283
+ # Check if it is an electron card
284
+ if card_type == :visa && credit_card.number =~ ELECTRON
285
+ CREDIT_CARDS[:electron]
286
+ else
287
+ CREDIT_CARDS[card_type]
288
+ end
289
+ end
290
+
291
+ # MMYY format
292
+ def format_date(month, year)
293
+ return nil if year.blank? || month.blank?
294
+
295
+ year = sprintf("%.4i", year)
296
+ month = sprintf("%.2i", month)
297
+
298
+ "#{month}#{year[-2..-1]}"
299
+ end
300
+
301
+ def commit(action, parameters)
302
+ response = parse( ssl_post(url_for(action), post_data(action, parameters)) )
303
+
304
+ Response.new(response["Status"] == APPROVED, message_from(response), response,
305
+ :test => test?,
306
+ :authorization => authorization_from(response, parameters, action),
307
+ :avs_result => {
308
+ :street_match => AVS_CVV_CODE[ response["AddressResult"] ],
309
+ :postal_match => AVS_CVV_CODE[ response["PostCodeResult"] ],
310
+ },
311
+ :cvv_result => AVS_CVV_CODE[ response["CV2Result"] ]
312
+ )
313
+ end
314
+
315
+ def authorization_from(response, params, action)
316
+ case action
317
+ when :store
318
+ response['Token']
319
+ else
320
+ [ params[:VendorTxCode],
321
+ response["VPSTxId"],
322
+ response["TxAuthNo"],
323
+ response["SecurityKey"],
324
+ action ].join(";")
325
+ end
326
+ end
327
+
328
+ def abort_or_void_from(identification)
329
+ original_transaction = identification.split(';').last
330
+ original_transaction == 'authorization' ? :abort : :void
331
+ end
332
+
333
+ def url_for(action)
334
+ simulate ? build_simulator_url(action) : build_url(action)
335
+ end
336
+
337
+ def build_url(action)
338
+ endpoint = case action
339
+ when :purchase, :authorization then "vspdirect-register"
340
+ when :store then 'directtoken'
341
+ else TRANSACTIONS[action].downcase
342
+ end
343
+ "#{test? ? self.test_url : self.live_url}/#{endpoint}.vsp"
344
+ end
345
+
346
+ def build_simulator_url(action)
347
+ endpoint = [ :purchase, :authorization ].include?(action) ? "VSPDirectGateway.asp" : "VSPServerGateway.asp?Service=Vendor#{TRANSACTIONS[action].capitalize}Tx"
348
+ "#{self.simulator_url}/#{endpoint}"
349
+ end
350
+
351
+ def message_from(response)
352
+ response['Status'] == APPROVED ? 'Success' : (response['StatusDetail'] || 'Unspecified error') # simonr 20080207 can't actually get non-nil blanks, so this is shorter
353
+ end
354
+
355
+ def post_data(action, parameters = {})
356
+ parameters.update(
357
+ :Vendor => @options[:login],
358
+ :TxType => TRANSACTIONS[action],
359
+ :VPSProtocol => @options.fetch(:protocol_version, '3.00')
360
+ )
361
+
362
+ if(application_id && (application_id != Gateway.application_id))
363
+ parameters.update(:ReferrerID => application_id)
364
+ end
365
+
366
+ parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
367
+ end
368
+
369
+ # SagePay returns data in the following format
370
+ # Key1=value1
371
+ # Key2=value2
372
+ def parse(body)
373
+ result = {}
374
+ body.to_s.each_line do |pair|
375
+ result[$1] = $2 if pair.strip =~ /\A([^=]+)=(.+)\Z/im
376
+ end
377
+ result
378
+ end
379
+
380
+ def add_pair(post, key, value, options = {})
381
+ post[key] = value if !value.blank? || options[:required]
382
+ end
383
+
384
+ def parse_first_and_last_name(value)
385
+ name = value.to_s.split(' ')
386
+
387
+ last_name = name.pop || ''
388
+ first_name = name.join(' ')
389
+ [ truncate(first_name, 20), truncate(last_name, 20) ]
390
+ end
391
+
392
+ def localized_amount(money, currency)
393
+ amount = amount(money)
394
+ CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s) ? amount.split('.').first : amount
395
+ end
396
+ end
397
+
398
+ end
399
+ end