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,183 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class ViaklixGateway < Gateway
4
+ class_attribute :test_url, :live_url, :delimiter, :actions
5
+
6
+ self.test_url = 'https://demo.viaklix.com/process.asp'
7
+ self.live_url = 'https://www.viaklix.com/process.asp'
8
+ self.delimiter = "\r\n"
9
+
10
+ self.actions = {
11
+ :purchase => 'SALE',
12
+ :credit => 'CREDIT'
13
+ }
14
+
15
+ APPROVED = '0'
16
+
17
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
18
+ self.supported_countries = ['US']
19
+ self.display_name = 'ViaKLIX'
20
+ self.homepage_url = 'http://viaklix.com'
21
+
22
+ # Initialize the Gateway
23
+ #
24
+ # The gateway requires that a valid login and password be passed
25
+ # in the +options+ hash.
26
+ #
27
+ # ==== Options
28
+ #
29
+ # * <tt>:login</tt> -- Merchant ID
30
+ # * <tt>:password</tt> -- PIN
31
+ # * <tt>:user</tt> -- Specify a subuser of the account (optional)
32
+ # * <tt>:test => +true+ or +false+</tt> -- Force test transactions
33
+ def initialize(options = {})
34
+ requires!(options, :login, :password)
35
+ super
36
+ end
37
+
38
+ # Make a purchase
39
+ def purchase(money, creditcard, options = {})
40
+ form = {}
41
+ add_invoice(form, options)
42
+ add_creditcard(form, creditcard)
43
+ add_address(form, options)
44
+ add_customer_data(form, options)
45
+ add_test_mode(form, options)
46
+ commit(:purchase, money, form)
47
+ end
48
+
49
+ # Make a credit to a card (Void can only be done from the virtual terminal)
50
+ # Viaklix does not support credits by reference. You must pass in the credit card
51
+ def credit(money, creditcard, options = {})
52
+ if creditcard.is_a?(String)
53
+ raise ArgumentError, "Reference credits are not supported. Please supply the original credit card"
54
+ end
55
+
56
+ form = {}
57
+ add_invoice(form, options)
58
+ add_creditcard(form, creditcard)
59
+ add_address(form, options)
60
+ add_customer_data(form, options)
61
+ add_test_mode(form, options)
62
+ commit(:credit, money, form)
63
+ end
64
+
65
+ private
66
+ def add_test_mode(form, options)
67
+ form[:test_mode] = 'TRUE' if options[:test_mode]
68
+ end
69
+
70
+ def add_customer_data(form, options)
71
+ form[:email] = options[:email].to_s.slice(0, 100) unless options[:email].blank?
72
+ form[:customer_code] = options[:customer].to_s.slice(0, 10) unless options[:customer].blank?
73
+ end
74
+
75
+ def add_invoice(form,options)
76
+ form[:invoice_number] = (options[:order_id] || options[:invoice]).to_s.slice(0, 10)
77
+ form[:description] = options[:description].to_s.slice(0, 255)
78
+ end
79
+
80
+ def add_address(form,options)
81
+ billing_address = options[:billing_address] || options[:address]
82
+
83
+ if billing_address
84
+ form[:avs_address] = billing_address[:address1].to_s.slice(0, 30)
85
+ form[:address2] = billing_address[:address2].to_s.slice(0, 30)
86
+ form[:avs_zip] = billing_address[:zip].to_s.slice(0, 10)
87
+ form[:city] = billing_address[:city].to_s.slice(0, 30)
88
+ form[:state] = billing_address[:state].to_s.slice(0, 10)
89
+ form[:company] = billing_address[:company].to_s.slice(0, 50)
90
+ form[:phone] = billing_address[:phone].to_s.slice(0, 20)
91
+ form[:country] = billing_address[:country].to_s.slice(0, 50)
92
+ end
93
+
94
+ if shipping_address = options[:shipping_address]
95
+ first_name, last_name = parse_first_and_last_name(shipping_address[:name])
96
+ form[:ship_to_first_name] = first_name.to_s.slice(0, 20)
97
+ form[:ship_to_last_name] = last_name.to_s.slice(0, 30)
98
+ form[:ship_to_address] = shipping_address[:address1].to_s.slice(0, 30)
99
+ form[:ship_to_city] = shipping_address[:city].to_s.slice(0, 30)
100
+ form[:ship_to_state] = shipping_address[:state].to_s.slice(0, 10)
101
+ form[:ship_to_company] = shipping_address[:company].to_s.slice(0, 50)
102
+ form[:ship_to_country] = shipping_address[:country].to_s.slice(0, 50)
103
+ form[:ship_to_zip] = shipping_address[:zip].to_s.slice(0, 10)
104
+ end
105
+ end
106
+
107
+ def parse_first_and_last_name(value)
108
+ name = value.to_s.split(' ')
109
+
110
+ last_name = name.pop || ''
111
+ first_name = name.join(' ')
112
+ [ first_name, last_name ]
113
+ end
114
+
115
+ def add_creditcard(form, creditcard)
116
+ form[:card_number] = creditcard.number
117
+ form[:exp_date] = expdate(creditcard)
118
+
119
+ if creditcard.verification_value?
120
+ add_verification_value(form, creditcard)
121
+ end
122
+
123
+ form[:first_name] = creditcard.first_name.to_s.slice(0, 20)
124
+ form[:last_name] = creditcard.last_name.to_s.slice(0, 30)
125
+ end
126
+
127
+ def add_verification_value(form, creditcard)
128
+ form[:cvv2cvc2] = creditcard.verification_value
129
+ form[:cvv2] = 'present'
130
+ end
131
+
132
+ def preamble
133
+ result = {
134
+ 'merchant_id' => @options[:login],
135
+ 'pin' => @options[:password],
136
+ 'show_form' => 'false',
137
+ 'result_format' => 'ASCII'
138
+ }
139
+
140
+ result['user_id'] = @options[:user] unless @options[:user].blank?
141
+ result
142
+ end
143
+
144
+ def commit(action, money, parameters)
145
+ parameters[:amount] = amount(money)
146
+ parameters[:transaction_type] = self.actions[action]
147
+
148
+ response = parse( ssl_post(test? ? self.test_url : self.live_url, post_data(parameters)) )
149
+
150
+ Response.new(response['result'] == APPROVED, message_from(response), response,
151
+ :test => @options[:test] || test?,
152
+ :authorization => authorization_from(response),
153
+ :avs_result => { :code => response['avs_response'] },
154
+ :cvv_result => response['cvv2_response']
155
+ )
156
+ end
157
+
158
+ def authorization_from(response)
159
+ response['txn_id']
160
+ end
161
+
162
+ def message_from(response)
163
+ response['result_message']
164
+ end
165
+
166
+ def post_data(parameters)
167
+ result = preamble
168
+ result.merge!(parameters)
169
+ result.collect { |key, value| "ssl_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
170
+ end
171
+
172
+ # Parse the response message
173
+ def parse(msg)
174
+ resp = {}
175
+ msg.split(self.delimiter).collect{|li|
176
+ key, value = li.split("=")
177
+ resp[key.strip.gsub(/^ssl_/, '')] = value.to_s.strip
178
+ }
179
+ resp
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,385 @@
1
+ require 'i18n/core_ext/string/interpolate'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+
6
+ # For more information on the Vindicia Gateway please visit their {website}[http://vindicia.com/]
7
+ #
8
+ # The login and password are not the username and password you use to
9
+ # login to the Vindicia Merchant Portal.
10
+ #
11
+ # ==== Recurring Billing
12
+ #
13
+ # AutoBills are an feature of Vindicia's API that allows for creating and managing subscriptions.
14
+ #
15
+ # For more information about Vindicia's API and various other services visit their {Resource Center}[http://www.vindicia.com/resources/index.html]
16
+ class VindiciaGateway < Gateway
17
+ self.supported_countries = %w{US CA GB AU MX BR DE KR CN HK}
18
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
19
+ self.homepage_url = 'http://www.vindicia.com/'
20
+ self.display_name = 'Vindicia'
21
+
22
+ class_attribute :test_url, :live_url
23
+
24
+ self.test_url = "https://soap.prodtest.sj.vindicia.com/soap.pl"
25
+ self.live_url = "http://soap.vindicia.com/soap.pl"
26
+
27
+ # Creates a new VindiciaGateway
28
+ #
29
+ # The gateway requires that a valid login and password be passed
30
+ # in the +options+ hash.
31
+ #
32
+ # ==== Options
33
+ #
34
+ # * <tt>:login</tt> -- Vindicia SOAP login (REQUIRED)
35
+ # * <tt>:password</tt> -- Vindicia SOAP password (REQUIRED)
36
+ # * <tt>:api_version</tt> -- Vindicia API Version - defaults to 3.6 (OPTIONAL)
37
+ # * <tt>:account_id</tt> -- Account Id which all transactions will be run against. (REQUIRED)
38
+ # * <tt>:transaction_prefix</tt> -- Prefix to order id for one-time transactions - defaults to 'X' (OPTIONAL
39
+ # * <tt>:min_chargeback_probability</tt> -- Minimum score for chargebacks - defaults to 65 (OPTIONAL)
40
+ # * <tt>:cvn_success</tt> -- Array of valid CVN Check return values - defaults to [M, P] (OPTIONAL)
41
+ # * <tt>:avs_success</tt> -- Array of valid AVS Check return values - defaults to [X, Y, A, W, Z] (OPTIONAL)
42
+ def initialize(options = {})
43
+ requires!(options, :login, :password, :account_id)
44
+ super
45
+
46
+ @account_id = options[:account_id]
47
+
48
+ @transaction_prefix = options[:transaction_prefix] || "X"
49
+
50
+ @min_chargeback_probability = options[:min_chargeback_probability] || 65
51
+ @cvn_success = options[:cvn_success] || %w{M P}
52
+ @avs_success = options[:avs_success] || %w{X Y A W Z}
53
+
54
+ @allowed_authorization_statuses = %w{Authorized}
55
+ end
56
+
57
+ # Perform a purchase, which is essentially an authorization and capture in a single operation.
58
+ #
59
+ # ==== Parameters
60
+ #
61
+ # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
62
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
63
+ # * <tt>options</tt> -- A hash of optional parameters.
64
+ def purchase(money, creditcard, options = {})
65
+ response = authorize(money, creditcard, options)
66
+ return response if !response.success? || response.fraud_review?
67
+
68
+ capture(money, response.authorization, options)
69
+ end
70
+
71
+ # Performs an authorization, which reserves the funds on the customer's credit card, but does not
72
+ # charge the card.
73
+ #
74
+ # ==== Parameters
75
+ #
76
+ # * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
77
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
78
+ # * <tt>options</tt> -- A hash of optional parameters.
79
+ def authorize(money, creditcard, options = {})
80
+ vindicia_transaction = authorize_transaction(money, creditcard, options)
81
+ response = check_transaction(vindicia_transaction)
82
+
83
+ # if this response is under fraud review because of our AVS/CVV checks void the transaction
84
+ if !response.success? && response.fraud_review? && !response.authorization.blank?
85
+ void_response = void([vindicia_transaction[:transaction][:merchantTransactionId]], options)
86
+ if void_response.success?
87
+ return response
88
+ else
89
+ return void_response
90
+ end
91
+ end
92
+
93
+ response
94
+ end
95
+
96
+ # Captures the funds from an authorized transaction.
97
+ #
98
+ # ==== Parameters
99
+ #
100
+ # * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
101
+ # * <tt>identification</tt> -- The authorization returned from the previous authorize request.
102
+ def capture(money, identification, options = {})
103
+ response = post(:capture) do |xml|
104
+ add_hash(xml, transactions: [{ merchantTransactionId: identification }])
105
+ end
106
+
107
+ if response[:return][:returnCode] != '200' || response[:qtyFail].to_i > 0
108
+ return fail(response)
109
+ end
110
+
111
+ success(response, identification)
112
+ end
113
+
114
+ # Void a previous transaction
115
+ #
116
+ # ==== Parameters
117
+ #
118
+ # * <tt>identification</tt> - The authorization returned from the previous authorize request.
119
+ # * <tt>options</tt> - Extra options (currently only :ip used)
120
+ def void(identification, options = {})
121
+ response = post(:cancel) do |xml|
122
+ add_hash(xml, transactions: [{
123
+ account: {merchantAccountId: @account_id},
124
+ merchantTransactionId: identification,
125
+ sourceIp: options[:ip]
126
+ }])
127
+ end
128
+
129
+ if response[:return][:returnCode] == '200' && response[:qtyFail].to_i == 0
130
+ success(response, identification)
131
+ else
132
+ fail(response)
133
+ end
134
+ end
135
+
136
+ # Perform a recurring billing, which is essentially a purchase and autobill setup in a single operation.
137
+ #
138
+ # ==== Parameters
139
+ #
140
+ # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
141
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
142
+ # * <tt>options</tt> -- A hash of parameters.
143
+ #
144
+ # ==== Options
145
+ #
146
+ # * <tt>:product_sku</tt> -- The subscription product's sku
147
+ # * <tt>:autobill_prefix</tt> -- Prefix to order id for subscriptions - defaults to 'A' (OPTIONAL)
148
+ def recurring(money, creditcard, options={})
149
+ ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
150
+
151
+ options[:recurring] = true
152
+ @autobill_prefix = options[:autobill_prefix] || "A"
153
+
154
+ response = authorize(money, creditcard, options)
155
+ return response if !response.success? || response.fraud_review?
156
+
157
+ capture_resp = capture(money, response.authorization, options)
158
+ return capture_resp if !response.success?
159
+
160
+ # Setting up a recurring AutoBill requires an associated product
161
+ requires!(options, :product_sku)
162
+ autobill_response = check_subscription(authorize_subscription(options.merge(:product_sku => options[:product_sku])))
163
+
164
+ if autobill_response.success?
165
+ autobill_response
166
+ else
167
+ # If the AutoBill fails to set-up, void the transaction and return it as the response
168
+ void_response = void(capture_resp.authorization, options)
169
+ if void_response.success?
170
+ return autobill_response
171
+ else
172
+ return void_response
173
+ end
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def add_hash(xml, hash)
180
+ hash.each do |k,v|
181
+ add_element(xml, k, v)
182
+ end
183
+ end
184
+
185
+ def add_array(xml, elem, val)
186
+ val.each do |v|
187
+ add_element(xml, elem, v)
188
+ end
189
+ end
190
+
191
+ def add_element(xml, elem, val)
192
+ if val.is_a?(Hash)
193
+ xml.tag!(elem.to_s.camelize(:lower)) do |env|
194
+ add_hash(env, val)
195
+ end
196
+ elsif val.is_a?(Array)
197
+ add_array(xml, elem, val)
198
+ else
199
+ xml.tag!(elem.to_s.camelize(:lower), val.to_s)
200
+ end
201
+ end
202
+
203
+ def post(action, kind="Transaction")
204
+ xml = Builder::XmlMarkup.new
205
+ xml.instruct!(:xml, :encoding => "UTF-8")
206
+ xml.env :Envelope,
207
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
208
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
209
+ "xmlns:tns" => "http://soap.vindicia.com/v3_6/#{kind}",
210
+ "xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/" do
211
+
212
+ xml.env :Body do
213
+ xml.tns action.to_sym do
214
+ xml.auth do
215
+ xml.tag! :login, @options[:login]
216
+ xml.tag! :password, @options[:password]
217
+ xml.tag! :version, "3.6"
218
+ end
219
+
220
+ yield(xml)
221
+ end
222
+ end
223
+ end
224
+
225
+ url = (test? ? self.test_url : self.live_url)
226
+ parse(ssl_post(url, xml.target!, "Content-Type" => "text/xml"))
227
+ end
228
+
229
+ def parse(response)
230
+ # Vindicia always returns in the form of request_type_response => { actual_response }
231
+ Hash.from_xml(response)["Envelope"]["Body"].values.first.with_indifferent_access
232
+ end
233
+
234
+ def check_transaction(vindicia_transaction)
235
+ if vindicia_transaction[:return][:returnCode] == '200'
236
+ status_log = vindicia_transaction[:transaction][:statusLog].first
237
+ if status_log[:creditCardStatus]
238
+ avs = status_log[:creditCardStatus][:avsCode]
239
+ cvn = status_log[:creditCardStatus][:cvnCode]
240
+ end
241
+
242
+ if @allowed_authorization_statuses.include?(status_log[:status]) &&
243
+ check_cvn(cvn) && check_avs(avs)
244
+
245
+ success(vindicia_transaction,
246
+ vindicia_transaction[:transaction][:merchantTransactionId],
247
+ avs, cvn)
248
+ else
249
+ # If the transaction is authorized, but it didn't pass our AVS/CVV checks send the authorization along so
250
+ # that is gets voided. Otherwise, send no authorization.
251
+ fail(vindicia_transaction, avs, cvn, false,
252
+ @allowed_authorization_statuses.include?(status_log[:status]) ? vindicia_transaction[:transaction][:merchantTransactionId] : "")
253
+ end
254
+ else
255
+ # 406 = Chargeback risk score is higher than minChargebackProbability, transaction not authorized.
256
+ fail(vindicia_transaction, nil, nil, vindicia_transaction[:return][:return_code] == '406')
257
+ end
258
+ end
259
+
260
+ def authorize_transaction(money, creditcard, options)
261
+ parameters = {
262
+ :amount => amount(money),
263
+ :currency => options[:currency] || currency(money)
264
+ }
265
+
266
+ add_account_data(parameters, options)
267
+ add_customer_data(parameters, options)
268
+ add_payment_source(parameters, creditcard, options)
269
+
270
+ post(:auth) do |xml|
271
+ add_hash(xml, transaction: parameters, minChargebackProbability: @min_chargeback_probability)
272
+ end
273
+ end
274
+
275
+ def add_account_data(parameters, options)
276
+ parameters[:account] = { :merchantAccountId => @account_id }
277
+ parameters[:sourceIp] = options[:ip] if options[:ip]
278
+ end
279
+
280
+ def add_customer_data(parameters, options)
281
+ parameters[:merchantTransactionId] = transaction_id(options[:order_id])
282
+ parameters[:shippingAddress] = convert_am_address_to_vindicia(options[:shipping_address])
283
+
284
+ # Transaction items must be provided for tax purposes
285
+ requires!(options, :line_items)
286
+ parameters[:transactionItems] = options[:line_items]
287
+
288
+ if options[:recurring]
289
+ parameters[:nameValues] = [{:name => 'merchantAutoBillIdentifier', :value => autobill_id(options[:order_id])}]
290
+ end
291
+ end
292
+
293
+ def add_payment_source(parameters, creditcard, options)
294
+ parameters[:sourcePaymentMethod] = {
295
+ :type => 'CreditCard',
296
+ :creditCard => { :account => creditcard.number, :expirationDate => "%4d%02d" % [creditcard.year, creditcard.month] },
297
+ :accountHolderName => creditcard.name,
298
+ :nameValues => [{ :name => 'CVN', :value => creditcard.verification_value }],
299
+ :billingAddress => convert_am_address_to_vindicia(options[:billing_address] || options[:address]),
300
+ :customerSpecifiedType => creditcard.brand.capitalize,
301
+ :active => !!options[:recurring]
302
+ }
303
+ end
304
+
305
+ def authorize_subscription(options)
306
+ parameters = {}
307
+
308
+ add_account_data(parameters, options)
309
+ add_subscription_information(parameters, options)
310
+
311
+ post(:update, "AutoBill") do |xml|
312
+ add_hash(xml, autobill: parameters, validatePaymentMethod: false, minChargebackProbability: 100)
313
+ end
314
+ end
315
+
316
+ def check_subscription(vindicia_transaction)
317
+ if vindicia_transaction[:return][:returnCode] == '200'
318
+ if vindicia_transaction[:autobill] && vindicia_transaction[:autobill][:status] == "Active"
319
+ success(vindicia_transaction,
320
+ vindicia_transaction[:autobill][:merchantAutoBillId])
321
+ else
322
+ fail(vindicia_transaction)
323
+ end
324
+ else
325
+ fail(vindicia_transaction)
326
+ end
327
+ end
328
+
329
+ def add_subscription_information(parameters, options)
330
+ requires!(options, :product_sku)
331
+
332
+ if options[:shipping_address]
333
+ parameters[:account][:shipping_address] = options[:shipping_address]
334
+ end
335
+
336
+ parameters[:merchantAutoBillId] = autobill_id(options[:order_id])
337
+ parameters[:product] = { :merchantProductId => options[:product_sku] }
338
+ end
339
+
340
+ def check_avs(avs)
341
+ avs.blank? || @avs_success.include?(avs)
342
+ end
343
+
344
+ def check_cvn(cvn)
345
+ cvn.blank? || @cvn_success.include?(cvn)
346
+ end
347
+
348
+ def success(response, authorization, avs_code = nil, cvn_code = nil)
349
+ ActiveMerchant::Billing::Response.new(true, response[:return][:returnString], response,
350
+ { :fraud_review => false, :authorization => authorization, :test => test?,
351
+ :avs_result => { :code => avs_code }, :cvv_result => cvn_code })
352
+ end
353
+
354
+ def fail(response, avs_code = nil, cvn_code = nil, fraud_review = false, authorization = "")
355
+ ActiveMerchant::Billing::Response.new(false, response[:return][:returnString], response,
356
+ { :fraud_review => fraud_review || !authorization.blank?,
357
+ :authorization => authorization, :test => test?,
358
+ :avs_result => { :code => avs_code }, :cvv_result => cvn_code })
359
+
360
+ end
361
+
362
+ def autobill_id(order_id)
363
+ "#{@autobill_prefix}#{order_id}"
364
+ end
365
+
366
+ def transaction_id(order_id)
367
+ "#{@transaction_prefix}#{order_id}"
368
+ end
369
+
370
+ # Converts valid ActiveMerchant address hash to proper Vindicia format
371
+ def convert_am_address_to_vindicia(address)
372
+ return if address.nil?
373
+
374
+ convs = { :address1 => :addr1, :address2 => :addr2,
375
+ :state => :district, :zip => :postalCode }
376
+
377
+ vindicia_address = {}
378
+ address.each do |key, val|
379
+ vindicia_address[convs[key] || key] = val
380
+ end
381
+ vindicia_address
382
+ end
383
+ end
384
+ end
385
+ end