activemerchant 1.1.0 → 1.2.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 (178) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +226 -0
  3. data/CONTRIBUTERS +52 -0
  4. data/README +34 -24
  5. data/Rakefile +152 -0
  6. data/gem-public_cert.pem +20 -0
  7. data/init.rb +3 -0
  8. data/lib/active_merchant.rb +3 -1
  9. data/lib/active_merchant/billing/credit_card.rb +21 -17
  10. data/lib/active_merchant/billing/credit_card_methods.rb +17 -19
  11. data/lib/active_merchant/billing/gateway.rb +160 -44
  12. data/lib/active_merchant/billing/gateways.rb +2 -15
  13. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -21
  14. data/lib/active_merchant/billing/gateways/bogus.rb +6 -6
  15. data/lib/active_merchant/billing/gateways/brain_tree.rb +191 -0
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +207 -0
  17. data/lib/active_merchant/billing/gateways/cyber_source.rb +402 -0
  18. data/lib/active_merchant/billing/gateways/data_cash.rb +41 -97
  19. data/lib/active_merchant/billing/gateways/efsnet.rb +256 -0
  20. data/lib/active_merchant/billing/gateways/eway.rb +77 -29
  21. data/lib/active_merchant/billing/gateways/exact.rb +230 -0
  22. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -33
  23. data/lib/active_merchant/billing/gateways/moneris.rb +155 -125
  24. data/lib/active_merchant/billing/gateways/net_registry.rb +257 -0
  25. data/lib/active_merchant/billing/gateways/pay_junction.rb +407 -0
  26. data/lib/active_merchant/billing/gateways/payflow.rb +163 -25
  27. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +56 -38
  28. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +10 -1
  29. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +9 -0
  30. data/lib/active_merchant/billing/gateways/payflow_express.rb +36 -11
  31. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +6 -0
  32. data/lib/active_merchant/billing/gateways/payflow_uk.rb +7 -3
  33. data/lib/active_merchant/billing/gateways/payment_express.rb +261 -0
  34. data/lib/active_merchant/billing/gateways/paypal.rb +18 -4
  35. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +31 -15
  36. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +8 -0
  37. data/lib/active_merchant/billing/gateways/paypal_express.rb +33 -8
  38. data/lib/active_merchant/billing/gateways/plugnpay.rb +300 -0
  39. data/lib/active_merchant/billing/gateways/protx.rb +285 -0
  40. data/lib/active_merchant/billing/gateways/psigate.rb +13 -12
  41. data/lib/active_merchant/billing/gateways/psl_card.rb +297 -0
  42. data/lib/active_merchant/billing/gateways/quickpay.rb +197 -0
  43. data/lib/active_merchant/billing/gateways/realex.rb +212 -0
  44. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  45. data/lib/active_merchant/billing/gateways/trans_first.rb +136 -0
  46. data/lib/active_merchant/billing/gateways/trust_commerce.rb +43 -20
  47. data/lib/active_merchant/billing/gateways/usa_epay.rb +6 -5
  48. data/lib/active_merchant/billing/gateways/verifi.rb +235 -0
  49. data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
  50. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +0 -2
  51. data/lib/active_merchant/billing/integrations/helper.rb +8 -1
  52. data/lib/active_merchant/billing/integrations/nochex.rb +62 -1
  53. data/lib/active_merchant/billing/integrations/nochex/notification.rb +9 -16
  54. data/lib/active_merchant/billing/integrations/notification.rb +1 -1
  55. data/lib/active_merchant/billing/integrations/paypal/helper.rb +59 -46
  56. data/lib/active_merchant/billing/integrations/paypal/notification.rb +14 -47
  57. data/lib/active_merchant/lib/error.rb +4 -0
  58. data/lib/active_merchant/lib/post_data.rb +22 -0
  59. data/lib/active_merchant/lib/posts_data.rb +23 -5
  60. data/lib/active_merchant/lib/requires_parameters.rb +2 -2
  61. data/lib/active_merchant/lib/validateable.rb +1 -1
  62. data/lib/support/gateway_support.rb +45 -0
  63. data/lib/tasks/cia.rb +1 -1
  64. data/script/generate +14 -0
  65. data/script/generator/base.rb +45 -0
  66. data/script/generator/generator.rb +24 -0
  67. data/script/generator/generators/gateway/gateway_generator.rb +14 -0
  68. data/script/generator/generators/gateway/templates/gateway.rb +73 -0
  69. data/script/generator/generators/gateway/templates/gateway_test.rb +41 -0
  70. data/script/generator/generators/gateway/templates/remote_gateway_test.rb +56 -0
  71. data/script/generator/generators/integration/integration_generator.rb +25 -0
  72. data/script/generator/generators/integration/templates/helper.rb +34 -0
  73. data/script/generator/generators/integration/templates/helper_test.rb +54 -0
  74. data/script/generator/generators/integration/templates/integration.rb +18 -0
  75. data/script/generator/generators/integration/templates/module_test.rb +9 -0
  76. data/script/generator/generators/integration/templates/notification.rb +100 -0
  77. data/script/generator/generators/integration/templates/notification_test.rb +41 -0
  78. data/script/generator/manifest.rb +20 -0
  79. data/test/extra/binding_of_caller.rb +80 -0
  80. data/test/extra/breakpoint.rb +547 -0
  81. data/test/fixtures.yml +251 -0
  82. data/test/remote_tests/remote_authorize_net_test.rb +113 -0
  83. data/test/remote_tests/remote_brain_tree_test.rb +78 -0
  84. data/test/remote_tests/remote_card_stream_test.rb +160 -0
  85. data/test/remote_tests/remote_cyber_source_test.rb +130 -0
  86. data/test/remote_tests/remote_data_cash_test.rb +155 -0
  87. data/test/remote_tests/remote_efsnet_test.rb +93 -0
  88. data/test/remote_tests/remote_eway_test.rb +71 -0
  89. data/test/remote_tests/remote_exact_test.rb +59 -0
  90. data/test/remote_tests/remote_gestpay_integration_test.rb +37 -0
  91. data/test/remote_tests/remote_linkpoint_test.rb +144 -0
  92. data/test/remote_tests/remote_moneris_test.rb +110 -0
  93. data/test/remote_tests/remote_net_registry_test.rb +120 -0
  94. data/test/remote_tests/remote_pay_junction_test.rb +162 -0
  95. data/test/remote_tests/remote_payflow_express_test.rb +50 -0
  96. data/test/remote_tests/remote_payflow_test.rb +241 -0
  97. data/test/remote_tests/remote_payflow_uk_test.rb +172 -0
  98. data/test/remote_tests/remote_payment_express_test.rb +136 -0
  99. data/test/remote_tests/remote_paypal_express_test.rb +49 -0
  100. data/test/remote_tests/remote_paypal_integration_test.rb +14 -0
  101. data/test/remote_tests/remote_paypal_test.rb +163 -0
  102. data/test/remote_tests/remote_plugnpay_test.rb +70 -0
  103. data/test/remote_tests/remote_protx_test.rb +184 -0
  104. data/test/remote_tests/remote_psigate_test.rb +87 -0
  105. data/test/remote_tests/remote_psl_card_test.rb +105 -0
  106. data/test/remote_tests/remote_quickpay_test.rb +182 -0
  107. data/test/remote_tests/remote_realex_test.rb +227 -0
  108. data/test/remote_tests/remote_secure_pay_test.rb +36 -0
  109. data/test/remote_tests/remote_trans_first_test.rb +37 -0
  110. data/test/remote_tests/remote_trust_commerce_test.rb +136 -0
  111. data/test/remote_tests/remote_usa_epay_test.rb +57 -0
  112. data/test/remote_tests/remote_verifi_test.rb +107 -0
  113. data/test/remote_tests/remote_viaklix_test.rb +53 -0
  114. data/test/test_helper.rb +132 -0
  115. data/test/unit/base_test.rb +61 -0
  116. data/test/unit/country_code_test.rb +33 -0
  117. data/test/unit/country_test.rb +64 -0
  118. data/test/unit/credit_card_formatting_test.rb +24 -0
  119. data/test/unit/credit_card_methods_test.rb +37 -0
  120. data/test/unit/credit_card_test.rb +365 -0
  121. data/test/unit/gateways/authorize_net_test.rb +140 -0
  122. data/test/unit/gateways/bogus_test.rb +43 -0
  123. data/test/unit/gateways/brain_tree_test.rb +77 -0
  124. data/test/unit/gateways/card_stream_test.rb +37 -0
  125. data/test/unit/gateways/cyber_source_test.rb +151 -0
  126. data/test/unit/gateways/data_cash_test.rb +23 -0
  127. data/test/unit/gateways/efsnet_test.rb +70 -0
  128. data/test/unit/gateways/eway_test.rb +105 -0
  129. data/test/unit/gateways/exact_test.rb +118 -0
  130. data/test/unit/gateways/gateway_test.rb +24 -0
  131. data/test/unit/gateways/linkpoint_test.rb +165 -0
  132. data/test/unit/gateways/moneris_test.rb +167 -0
  133. data/test/unit/gateways/net_registry_test.rb +478 -0
  134. data/test/unit/gateways/pay_junction_test.rb +61 -0
  135. data/test/unit/gateways/payflow_express_test.rb +165 -0
  136. data/test/unit/gateways/payflow_express_uk_test.rb +14 -0
  137. data/test/unit/gateways/payflow_test.rb +230 -0
  138. data/test/unit/gateways/payflow_uk_test.rb +68 -0
  139. data/test/unit/gateways/payment_express_test.rb +215 -0
  140. data/test/unit/gateways/paypal_express_test.rb +222 -0
  141. data/test/unit/gateways/paypal_test.rb +241 -0
  142. data/test/unit/gateways/plugnpay_test.rb +79 -0
  143. data/test/unit/gateways/protx_test.rb +110 -0
  144. data/test/unit/gateways/psigate_test.rb +110 -0
  145. data/test/unit/gateways/psl_card_test.rb +51 -0
  146. data/test/unit/gateways/quickpay_test.rb +125 -0
  147. data/test/unit/gateways/realex_test.rb +150 -0
  148. data/test/unit/gateways/secure_pay_test.rb +78 -0
  149. data/test/unit/gateways/trans_first_test.rb +125 -0
  150. data/test/unit/gateways/trust_commerce_test.rb +57 -0
  151. data/test/unit/gateways/usa_epay_test.rb +117 -0
  152. data/test/unit/gateways/verifi_test.rb +91 -0
  153. data/test/unit/gateways/viaklix_test.rb +72 -0
  154. data/test/unit/integrations/action_view_helper_test.rb +54 -0
  155. data/test/unit/integrations/bogus_module_test.rb +16 -0
  156. data/test/unit/integrations/chronopay_module_test.rb +9 -0
  157. data/test/unit/integrations/gestpay_module_test.rb +10 -0
  158. data/test/unit/integrations/helpers/bogus_helper_test.rb +28 -0
  159. data/test/unit/integrations/helpers/chronopay_helper_test.rb +67 -0
  160. data/test/unit/integrations/helpers/gestpay_helper_test.rb +100 -0
  161. data/test/unit/integrations/helpers/nochex_helper_test.rb +53 -0
  162. data/test/unit/integrations/helpers/paypal_helper_test.rb +162 -0
  163. data/test/unit/integrations/helpers/two_checkout_helper_test.rb +92 -0
  164. data/test/unit/integrations/nochex_module_test.rb +9 -0
  165. data/test/unit/integrations/notifications/chronopay_notification_test.rb +66 -0
  166. data/test/unit/integrations/notifications/gestpay_notification_test.rb +60 -0
  167. data/test/unit/integrations/notifications/nochex_notification_test.rb +51 -0
  168. data/test/unit/integrations/notifications/notification_test.rb +41 -0
  169. data/test/unit/integrations/notifications/paypal_notification_test.rb +85 -0
  170. data/test/unit/integrations/notifications/two_checkout_notification_test.rb +55 -0
  171. data/test/unit/integrations/paypal_module_test.rb +24 -0
  172. data/test/unit/integrations/two_checkout_module_test.rb +9 -0
  173. data/test/unit/post_data_test.rb +55 -0
  174. data/test/unit/response_test.rb +14 -0
  175. data/test/unit/validateable_test.rb +56 -0
  176. metadata +160 -7
  177. metadata.gz.sig +0 -0
  178. data/lib/active_merchant/billing/gateways/payflow/f73e89fd.0 +0 -17
@@ -15,14 +15,11 @@ module ActiveMerchant #:nodoc:
15
15
  # First, make sure you have everything setup correctly and all of your dependencies in place with:
16
16
  #
17
17
  # require 'rubygems'
18
- # require 'money'
19
18
  # require 'active_merchant'
20
19
  #
21
- # The second line is a require for the 'money' library. Make sure you have it installed with 'gem install money'
20
+ # ActiveMerchant expects amounts to be Integer values in cents
22
21
  #
23
- # Using the money library, create a money object. Pass the dollar value in cents. In this case, $10 US becomes 1000.
24
- #
25
- # tendollar = Money.us_dollar(1000)
22
+ # tendollar = 1000
26
23
  #
27
24
  # Next, create a credit card object using a TC approved test card.
28
25
  #
@@ -103,42 +100,60 @@ module ActiveMerchant #:nodoc:
103
100
  attr_reader :options
104
101
 
105
102
  self.money_format = :cents
103
+ self.supported_cardtypes = [:visa, :master, :discover, :american_express, :diners_club, :jcb]
104
+ self.supported_countries = ['US']
105
+ self.homepage_url = 'http://www.trustcommerce.com/'
106
+ self.display_name = 'TrustCommerce'
106
107
 
108
+ # Creates a new TrustCommerceGateway
109
+ #
110
+ # The gateway requires that a valid login and password be passed
111
+ # in the +options+ hash.
112
+ #
113
+ # ==== Options
114
+ #
115
+ # * <tt>:login</tt> -- The TrustCommerce account login.
116
+ # * <tt>:password</tt> -- The TrustCommerce account password.
117
+ # * <tt>:test => +true+ or +false+</tt> -- Perform test transactions
118
+ #
119
+ # ==== Test Account Credentials
120
+ # * <tt>:login</tt> -- TestMerchant
121
+ # * <tt>:password</tt> -- password
107
122
  def initialize(options = {})
108
123
  requires!(options, :login, :password)
109
- # these are the defaults for trustcommerce
110
- @options = {
111
- :login => "TestMerchant",
112
- :password => "password"
113
- }.update(options)
114
-
124
+
125
+ @options = options
115
126
  super
116
127
  end
117
128
 
129
+ def test?
130
+ @options[:test] || Base.gateway_mode == :test
131
+ end
132
+
118
133
  # authorize() is the first half of the preauth(authorize)/postauth(capture) model. The TC API docs call this
119
134
  # preauth, we preserve active_merchant's nomenclature of authorize() for consistency with the rest of the library. This
120
135
  # method simply checks to make sure funds are available for a transaction, and returns a transid that can be used later to
121
136
  # postauthorize (capture) the funds.
122
137
 
123
- def authorize(money, creditcard, options = {})
138
+ def authorize(money, creditcard_or_billing_id, options = {})
124
139
  parameters = {
125
140
  :amount => amount(money),
126
141
  }
127
142
 
128
- add_creditcard(parameters, creditcard)
143
+ add_payment_source(parameters, creditcard_or_billing_id)
129
144
  add_address(parameters, options)
130
145
  commit('preauth', parameters)
131
146
  end
132
147
 
133
148
  # purchase() is a simple sale. This is one of the most common types of transactions, and is extremely simple. All that you need
134
- # to process a purchase are an amount in cents or a money object and a creditcard object.
149
+ # to process a purchase are an amount in cents or a money object and a creditcard object or billingid string.
135
150
 
136
- def purchase(money, creditcard, options = {})
151
+ def purchase(money, creditcard_or_billing_id, options = {})
137
152
  parameters = {
138
153
  :amount => amount(money),
139
154
  }
140
155
 
141
- add_creditcard(parameters, creditcard)
156
+ add_payment_source(parameters, creditcard_or_billing_id)
142
157
  add_address(parameters, options)
143
158
  commit('sale', parameters)
144
159
  end
@@ -235,12 +250,16 @@ module ActiveMerchant #:nodoc:
235
250
 
236
251
  commit('unstore', parameters)
237
252
  end
238
-
239
- def self.supported_cardtypes
240
- [:visa, :master, :discover, :american_express, :diners_club, :jcb]
253
+
254
+ private
255
+ def add_payment_source(params, source)
256
+ if source.is_a?(String)
257
+ add_billing_id(params, source)
258
+ else
259
+ add_creditcard(params, source)
260
+ end
241
261
  end
242
262
 
243
- private
244
263
  def expdate(creditcard)
245
264
  year = sprintf("%.4i", creditcard.year)
246
265
  month = sprintf("%.2i", creditcard.month)
@@ -256,6 +275,10 @@ module ActiveMerchant #:nodoc:
256
275
  params[:cvv] = creditcard.verification_value if creditcard.verification_value?
257
276
  end
258
277
 
278
+ def add_billing_id(params, billingid)
279
+ params[:billingid] = billingid
280
+ end
281
+
259
282
  def add_address(params, options)
260
283
  address = options[:billing_address] || options[:address]
261
284
 
@@ -8,6 +8,11 @@ module ActiveMerchant #:nodoc:
8
8
  attr_reader :url
9
9
  attr_reader :response
10
10
  attr_reader :options
11
+
12
+ self.supported_cardtypes = [:visa, :master, :american_express]
13
+ self.supported_countries = ['US']
14
+ self.homepage_url = 'http://www.usa_epay.com/'
15
+ self.display_name = 'USA ePay'
11
16
 
12
17
  def initialize(options = {})
13
18
  requires!(options, :login)
@@ -39,11 +44,7 @@ module ActiveMerchant #:nodoc:
39
44
  post = {:refNum => authorization}
40
45
  commit('capture', money, post)
41
46
  end
42
-
43
- def self.supported_cardtypes
44
- [:visa, :master, :american_express]
45
- end
46
-
47
+
47
48
  private
48
49
 
49
50
  def expdate(creditcard)
@@ -0,0 +1,235 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class VerifiGateway < Gateway
6
+ class VerifiPostData < PostData
7
+ # Fields that will be send even if they are blank
8
+ self.required_fields = [ :amount, :type, :ccnumber, :ccexp, :firstname, :lastname,
9
+ :company, :address1, :address2, :city, :state, :zip, :country, :phone ]
10
+ end
11
+
12
+ URL = 'https://secure.verifi.com/gw/api/transact.php'
13
+
14
+ RESPONSE_CODE_MESSAGES = {
15
+ "100" => "Transaction was Approved",
16
+ "200" => "Transaction was Declined by Processor",
17
+ "201" => "Do Not Honor",
18
+ "202" => "Insufficient Funds",
19
+ "203" => "Over Limit",
20
+ "204" => "Transaction not allowed",
21
+ "220" => "Incorrect payment Data",
22
+ "221" => "No Such Card Issuer",
23
+ "222" => "No Card Number on file with Issuer",
24
+ "223" => "Expired Card",
25
+ "224" => "Invalid Expiration Date",
26
+ "225" => "Invalid Card Security Code",
27
+ "240" => "Call Issuer for Further Information",
28
+ "250" => "Pick Up Card",
29
+ "251" => "Lost Card",
30
+ "252" => "Stolen Card",
31
+ "253" => "Fraudulent Card",
32
+ "260" => "Declined With further Instructions Available (see response text)",
33
+ "261" => "Declined - Stop All Recurring Payments",
34
+ "262" => "Declined - Stop this Recurring Program",
35
+ "263" => "Declined - Update Cardholder Data Available",
36
+ "264" => "Declined - Retry in a few days",
37
+ "300" => "Transaction was Rejected by Gateway",
38
+ "400" => "Transaction Error Returned by Processor",
39
+ "410" => "Invalid Merchant Configuration",
40
+ "411" => "Merchant Account is Inactive",
41
+ "420" => "Communication Error",
42
+ "421" => "Communication Error with Issuer",
43
+ "430" => "Duplicate Transaction at Processor",
44
+ "440" => "Processor Format Error",
45
+ "441" => "Invalid Transaction Information",
46
+ "460" => "Processor Feature Not Available",
47
+ "461" => "Unsupported Card Type"
48
+ }
49
+
50
+ SUCCESS = 1
51
+
52
+ TRANSACTIONS = {
53
+ :authorization => 'auth',
54
+ :purchase => 'sale',
55
+ :capture => 'capture',
56
+ :void => 'void',
57
+ :credit => 'credit',
58
+ :refund => 'refund'
59
+ }
60
+
61
+ self.supported_countries = ['US']
62
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
63
+ self.homepage_url = 'http://www.verifi.com/'
64
+ self.display_name = 'Verifi'
65
+
66
+ attr_reader :url
67
+ attr_reader :response
68
+ attr_reader :options
69
+
70
+ def initialize(options = {})
71
+ requires!(options, :login, :password)
72
+ @options = options
73
+ super
74
+ end
75
+
76
+ def purchase(money, creditcard, options = {})
77
+ sale_authorization_or_credit_template(:purchase, money, creditcard, options)
78
+ end
79
+
80
+ def authorize(money, creditcard, options = {})
81
+ sale_authorization_or_credit_template(:authorization, money, creditcard, options)
82
+ end
83
+
84
+ def capture(money, authorization, options = {})
85
+ capture_void_or_refund_template(:capture, money, authorization, options)
86
+ end
87
+
88
+ def void(authorization, options = {})
89
+ capture_void_or_refund_template(:void, 0, authorization, options)
90
+ end
91
+
92
+ def credit(money, creditcard_or_authorization, options = {})
93
+ if creditcard_or_authorization.is_a?(String)
94
+ capture_void_or_refund_template(:refund, money, creditcard_or_authorization, options)
95
+ else
96
+ sale_authorization_or_credit_template(:credit, money, creditcard_or_authorization, options)
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def sale_authorization_or_credit_template(trx_type, money, creditcard, options = {})
103
+ post = VerifiPostData.new
104
+ add_security_key_data(post, options, money)
105
+ add_creditcard(post, creditcard)
106
+ add_addresses(post, options)
107
+ add_customer_data(post, options)
108
+ add_invoice_data(post, options)
109
+ add_optional_data(post, options)
110
+ commit(trx_type, money, post)
111
+ end
112
+
113
+ def capture_void_or_refund_template(trx_type, money, authorization, options)
114
+ post = VerifiPostData.new
115
+ post[:transactionid] = authorization
116
+
117
+ commit(trx_type, money, post)
118
+ end
119
+
120
+ def add_creditcard(post, creditcard)
121
+ post[:ccnumber] = creditcard.number
122
+ post[:ccexp] = expdate(creditcard)
123
+ post[:firstname] = creditcard.first_name
124
+ post[:lastname] = creditcard.last_name
125
+ post[:cvv] = creditcard.verification_value
126
+ end
127
+
128
+ def expdate(creditcard)
129
+ year = sprintf("%.4i", creditcard.year)
130
+ month = sprintf("%.2i", creditcard.month)
131
+
132
+ "#{month}#{year[-2..-1]}"
133
+ end
134
+
135
+ def add_addresses(post, options)
136
+ if billing_address = options[:billing_address] || options[:address]
137
+ post[:company] = billing_address[:company]
138
+ post[:address1] = billing_address[:address1]
139
+ post[:address2] = billing_address[:address2]
140
+ post[:city] = billing_address[:city]
141
+ post[:state] = billing_address[:state]
142
+ post[:zip] = billing_address[:zip]
143
+ post[:country] = billing_address[:country]
144
+ post[:phone] = billing_address[:phone]
145
+ post[:fax] = billing_address[:fax]
146
+ end
147
+
148
+ if shipping_address = options[:shipping_address] || billing_address
149
+ post[:shipping_firstname] = shipping_address[:first_name]
150
+ post[:shipping_lastname] = shipping_address[:last_name]
151
+ post[:shipping_company] = shipping_address[:company]
152
+ post[:shipping_address1] = shipping_address[:address1]
153
+ post[:shipping_address2] = shipping_address[:address2]
154
+ post[:shipping_city] = shipping_address[:city]
155
+ post[:shipping_state] = shipping_address[:state]
156
+ post[:shipping_zip] = shipping_address[:zip]
157
+ post[:shipping_country] = shipping_address[:country]
158
+ post[:shipping_email] = shipping_address[:email]
159
+ end
160
+ end
161
+
162
+ def add_customer_data(post, options)
163
+ post[:email] = options[:email]
164
+ post[:ipaddress] = options[:ip]
165
+ end
166
+
167
+ def add_invoice_data(post, options)
168
+ post[:orderid] = options[:order_id]
169
+ post[:ponumber] = options[:invoice]
170
+ post[:orderdescription] = options[:description]
171
+ post[:tax] = options[:tax]
172
+ post[:shipping] = options[:shipping]
173
+ end
174
+
175
+ def add_optional_data(post, options)
176
+ post[:billing_method] = options[:billing_method]
177
+ post[:website] = options[:website]
178
+ post[:descriptor] = options[:descriptor]
179
+ post[:descriptor_phone] = options[:descriptor_phone]
180
+ post[:cardholder_auth] = options[:cardholder_auth]
181
+ post[:cavv] = options[:cavv]
182
+ post[:xid] = options[:xid]
183
+ post[:customer_receipt] = options[:customer_receipt]
184
+ end
185
+
186
+ def add_security_key_data(post, options, money)
187
+ # MD5(username|password|orderid|amount|time)
188
+ now = Time.now.to_i.to_s
189
+ md5 = Digest::MD5.new
190
+ md5 << @options[:login].to_s + "|"
191
+ md5 << @options[:password].to_s + "|"
192
+ md5 << options[:order_id].to_s + "|"
193
+ md5 << amount(money).to_s + "|"
194
+ md5 << now
195
+ post[:key] = md5.hexdigest
196
+ post[:time] = now
197
+ end
198
+
199
+ def commit(trx_type, money, post)
200
+
201
+ post[:amount] = amount(money)
202
+
203
+ if result = test_result_from_cc_number(post[:ccnumber])
204
+ return result
205
+ end
206
+
207
+ data = ssl_post(URL, post_data(trx_type, post), 'Content-type' => "application/x-www-form-urlencoded")
208
+ @response = parse(data)
209
+
210
+ success = @response[:response].to_i == SUCCESS
211
+ message = @response[:response_code_message] ? @response[:response_code_message] : ""
212
+
213
+ Response.new(success, message, @response,
214
+ :test => test?,
215
+ :authorization => @response[:transactionid]
216
+ )
217
+ end
218
+
219
+ def parse(body)
220
+ results = {}
221
+ CGI.parse(body).each { |key, value| results[key.intern] = value[0] }
222
+ results[:response_code_message] = RESPONSE_CODE_MESSAGES[results[:response_code]] if results[:response_code]
223
+ results
224
+ end
225
+
226
+ def post_data(trx_type, post)
227
+ post[:username] = @options[:login]
228
+ post[:password] = @options[:password]
229
+ post[:type] = TRANSACTIONS[trx_type]
230
+
231
+ post.to_s
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,171 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class ViaklixGateway < Gateway
4
+ TEST_URL = 'https://demo.viaklix.com/process.asp'
5
+ LIVE_URL = 'https://www.viaklix.com/process.asp'
6
+
7
+ APPROVED = '0'
8
+
9
+ self.supported_cardtypes = [:visa, :master, :american_express]
10
+ self.supported_countries = ['US']
11
+ self.display_name = 'ViaKLIX'
12
+ self.homepage_url = 'http://viaklix.com'
13
+
14
+ # Initialize the Gateway
15
+ #
16
+ # The gateway requires that a valid login and password be passed
17
+ # in the +options+ hash.
18
+ #
19
+ # ==== Options
20
+ #
21
+ # * <tt>:login</tt> -- Merchant ID
22
+ # * <tt>:password</tt> -- PIN
23
+ # * <tt>:user</tt> -- Specify a subuser of the account (optional)
24
+ # * <tt>:test => +true+ or +false+</tt> -- Force test transactions
25
+ def initialize(options = {})
26
+ requires!(options, :login, :password)
27
+ @options = options
28
+ super
29
+ end
30
+
31
+ # Make a purchase
32
+ def purchase(money, creditcard, options = {})
33
+ form = {}
34
+ add_invoice(form, options)
35
+ add_creditcard(form, creditcard)
36
+ add_address(form, options)
37
+ add_customer_data(form, options)
38
+ commit('SALE', money, form)
39
+ end
40
+
41
+ # Make a credit to a card (Void can only be done from the virtual terminal)
42
+ # Viaklix does not support credits by reference. You must pass in the credit card
43
+ def credit(money, creditcard, options = {})
44
+ if creditcard.is_a?(String)
45
+ raise ArgumentError, "Reference credits are not supported. Please supply the original credit card"
46
+ end
47
+
48
+ form = {}
49
+ add_invoice(form, options)
50
+ add_creditcard(form, creditcard)
51
+ add_address(form, options)
52
+ add_customer_data(form, options)
53
+ commit('CREDIT', money, form)
54
+ end
55
+
56
+ private
57
+ def add_customer_data(form, options)
58
+ form[:email] = options[:email] unless options[:email].blank?
59
+ form[:customer_code] = options[:customer].to_s.slice(0, 17) unless options[:customer].blank?
60
+ end
61
+
62
+ def add_invoice(form,options)
63
+ form[:invoice_number] = options[:order_id] || options[:invoice]
64
+ end
65
+
66
+ def add_address(form,options)
67
+ billing_address = options[:billing_address] || options[:address]
68
+
69
+ if billing_address
70
+ form[:avs_address] = billing_address[:address1]
71
+ form[:avs_zip] = billing_address[:zip]
72
+ form[:city] = billing_address[:city]
73
+ form[:state] = billing_address[:state]
74
+ form[:company] = billing_address[:company]
75
+ form[:phone] = billing_address[:phone]
76
+ form[:country] = billing_address[:country]
77
+ end
78
+
79
+ shipping_address = options[:shipping_address] || billing_address
80
+
81
+ if shipping_address
82
+ first_name, last_name = parse_first_and_last_name(shipping_address[:name])
83
+ form[:ship_to_first_name] = first_name
84
+ form[:ship_to_last_name] = last_name
85
+ form[:ship_to_address] = shipping_address[:address1]
86
+ form[:ship_to_city] = shipping_address[:city]
87
+ form[:ship_to_state] = shipping_address[:state]
88
+ form[:ship_to_company] = shipping_address[:company]
89
+ form[:ship_to_country] = shipping_address[:country]
90
+ form[:ship_to_zip] = shipping_address[:zip]
91
+ end
92
+ end
93
+
94
+ def parse_first_and_last_name(value)
95
+ name = value.to_s.split(' ')
96
+
97
+ last_name = name.pop || ''
98
+ first_name = name.join(' ')
99
+ [ first_name, last_name ]
100
+ end
101
+
102
+ def add_creditcard(form, creditcard)
103
+ form[:card_number] = creditcard.number
104
+ form[:exp_date] = expdate(creditcard)
105
+
106
+ if creditcard.verification_value?
107
+ form[:cvv2cvc2] = creditcard.verification_value
108
+ form[:cvv2] = 'present'
109
+ end
110
+
111
+ form[:first_name] = creditcard.first_name
112
+ form[:last_name] = creditcard.last_name
113
+ end
114
+
115
+ def preamble
116
+ result = {
117
+ 'merchant_id' => @options[:login],
118
+ 'pin' => @options[:password],
119
+ 'show_form' => 'false',
120
+ 'test_mode' => @options[:test] ? 'TRUE' : 'FALSE',
121
+ 'result_format' => 'ASCII',
122
+ }
123
+
124
+ result['user_id'] = @options[:user] unless @options[:user].blank?
125
+ result
126
+ end
127
+
128
+ def commit(action, money, parameters)
129
+ if result = test_result_from_cc_number(parameters[:card_number])
130
+ return result
131
+ end
132
+
133
+ parameters[:amount] = amount(money)
134
+ parameters[:transaction_type] = action
135
+
136
+ msg = ssl_post(test? ? TEST_URL : LIVE_URL, post_data(parameters))
137
+
138
+ @response = parse(msg)
139
+ success = @response['result'] == APPROVED
140
+ message = @response['result_message']
141
+
142
+ Response.new(success, message, @response,
143
+ :test => @options[:test] || test?,
144
+ :authorization => @response['txn_id']
145
+ )
146
+ end
147
+
148
+ def post_data(parameters)
149
+ result = preamble
150
+ result.merge!(parameters)
151
+ result.collect { |key, value| "ssl_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
152
+ end
153
+
154
+ def expdate(creditcard)
155
+ year = sprintf("%.4i", creditcard.year)
156
+ month = sprintf("%.2i", creditcard.month)
157
+ "#{month}#{year[2..3]}"
158
+ end
159
+
160
+ # Parse the response message
161
+ def parse(msg)
162
+ resp = Hash.new;
163
+ msg.split("\r\n").collect{|li|
164
+ key, value = li.split("=")
165
+ resp[key.gsub(/^ssl_/, '')] = value.to_s.strip
166
+ }
167
+ resp
168
+ end
169
+ end
170
+ end
171
+ end