activemerchant 1.21.0 → 1.22.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 (55) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +63 -0
  3. data/CONTRIBUTORS +29 -0
  4. data/README.md +195 -0
  5. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -0
  6. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +2 -2
  7. data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -11
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -19
  9. data/lib/active_merchant/billing/gateways/certo_direct.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/cyber_source.rb +342 -106
  11. data/lib/active_merchant/billing/gateways/elavon.rb +2 -0
  12. data/lib/active_merchant/billing/gateways/epay.rb +3 -1
  13. data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
  14. data/lib/active_merchant/billing/gateways/migs.rb +259 -0
  15. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  16. data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
  17. data/lib/active_merchant/billing/gateways/ogone.rb +104 -12
  18. data/lib/active_merchant/billing/gateways/orbital.rb +15 -6
  19. data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -4
  20. data/lib/active_merchant/billing/gateways/payflow.rb +8 -3
  21. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -1
  22. data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -2
  23. data/lib/active_merchant/billing/gateways/payment_express.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/paypal.rb +3 -18
  25. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +287 -1
  26. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
  27. data/lib/active_merchant/billing/gateways/paypal_express.rb +14 -66
  28. data/lib/active_merchant/billing/gateways/realex.rb +5 -7
  29. data/lib/active_merchant/billing/gateways/stripe.rb +1 -9
  30. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -2
  31. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -5
  32. data/lib/active_merchant/billing/gateways/viaklix.rb +7 -2
  33. data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
  34. data/lib/active_merchant/billing/integrations/dotpay.rb +22 -0
  35. data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
  36. data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
  37. data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
  38. data/lib/active_merchant/billing/integrations/epay.rb +21 -0
  39. data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
  40. data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
  41. data/lib/active_merchant/billing/integrations/paypal/notification.rb +2 -1
  42. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +2 -3
  43. data/lib/active_merchant/billing/integrations/robokassa.rb +49 -0
  44. data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
  45. data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
  46. data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
  47. data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -0
  48. data/lib/active_merchant/billing/integrations/two_checkout.rb +25 -3
  49. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +15 -0
  50. data/lib/active_merchant/billing/integrations/verkkomaksut.rb +20 -0
  51. data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
  52. data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
  53. data/lib/active_merchant/version.rb +1 -1
  54. metadata +59 -26
  55. metadata.gz.sig +0 -0
@@ -59,6 +59,7 @@ module ActiveMerchant #:nodoc:
59
59
  add_creditcard(form, creditcard)
60
60
  add_address(form, options)
61
61
  add_customer_data(form, options)
62
+ add_test_mode(form, options)
62
63
  commit(:authorize, money, form)
63
64
  end
64
65
 
@@ -77,6 +78,7 @@ module ActiveMerchant #:nodoc:
77
78
  add_invoice(form, options)
78
79
  add_creditcard(form, options[:credit_card])
79
80
  add_customer_data(form, options)
81
+ add_test_mode(form, options)
80
82
  commit(:capture, money, form)
81
83
  end
82
84
 
@@ -192,7 +192,9 @@ module ActiveMerchant #:nodoc:
192
192
  else
193
193
  return {
194
194
  'accept' => '0',
195
- 'errortext' => 'No Location header returned.'
195
+ 'errortext' => 'ePay did not respond as expected. Please try again.',
196
+ 'response_code' => response.code,
197
+ 'response_message' => response.message
196
198
  }
197
199
  end
198
200
 
@@ -0,0 +1,450 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # iTransact, Inc. is an authorized reseller of the PaymentClearing gateway. If your merchant service provider uses PaymentClearing.com to process payments, you can use this module.
6
+ #
7
+ #
8
+ # Please note, the username and API Access Key are not what you use to log into the Merchant Control Panel.
9
+ #
10
+ # ==== How to get your GatewayID and API Access Key
11
+ #
12
+ # 1. If you don't already have a Gateway Account, go to http://www.itransact.com/merchant/test.html to sign up.
13
+ # 2. Go to http://support.paymentclearing.com and login or register, if necessary.
14
+ # 3. Click on "Submit a Ticket."
15
+ # 4. Select "Merchant Support" as the department and click "Next"
16
+ # 5. Enter *both* your company name and GatewayID. Put "API Access Key" in the subject. In the body, you can request a username, but it may already be in use.
17
+ #
18
+ # ==== Initialization
19
+ #
20
+ # Once you have the username, API Access Key, and your GatewayId, you're ready
21
+ # to begin. You initialize the Gateway like so:
22
+ #
23
+ # gateway = ActiveMerchant::Billing::ItransactGateway.new(
24
+ # :login => "#{THE_USERNAME}",
25
+ # :password => "#{THE_API_ACCESS_KEY}",
26
+ # :gateway_id => "#{THE_GATEWAY_ID}"
27
+ # )
28
+ #
29
+ # ==== Important Notes
30
+ # 1. Recurring is not implemented
31
+ # 1. CreditTransactions are not implemented (these are credits not related to a previously run transaction).
32
+ # 1. TransactionStatus is not implemented
33
+ #
34
+ class ItransactGateway < Gateway
35
+ URL = 'https://secure.paymentclearing.com/cgi-bin/rc/xmltrans2.cgi'
36
+
37
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
38
+ self.supported_countries = ['US']
39
+
40
+ # The card types supported by the payment gateway
41
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
42
+
43
+ # The homepage URL of the gateway
44
+ self.homepage_url = 'http://www.itransact.com/'
45
+
46
+ # The name of the gateway
47
+ self.display_name = 'iTransact'
48
+
49
+ #
50
+ # Creates a new instance of the iTransact Gateway.
51
+ #
52
+ # ==== Parameters
53
+ # * <tt>options</tt> - A Hash of options
54
+ #
55
+ # ==== Options Hash
56
+ # * <tt>:login</tt> - A String containing your PaymentClearing assigned API Access Username
57
+ # * <tt>:password</tt> - A String containing your PaymentClearing assigned API Access Key
58
+ # * <tt>:gateway_id</tt> - A String containing your PaymentClearing assigned GatewayID
59
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Run *all* transactions with the 'TestMode' element set to 'TRUE'.
60
+ #
61
+ def initialize(options = {})
62
+ requires!(options, :login, :password, :gateway_id)
63
+ @options = options
64
+ super
65
+ end
66
+
67
+ # Performs an authorize transaction. In PaymentClearing's documentation
68
+ # this is known as a "PreAuth" transaction.
69
+ #
70
+ # ==== Parameters
71
+ # * <tt>money</tt> - The amount to be captured. Should be an Integer amount in cents.
72
+ # * <tt>creditcard</tt> - The CreditCard details for the transaction
73
+ # * <tt>options</tt> - A Hash of options
74
+ #
75
+ # ==== Options Hash
76
+ # The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
77
+ # * <tt>:order_items</tt> - An Array of Hash objects with the keys <tt>:description</tt>, <tt>:cost</tt> (in cents!), and <tt>:quantity</tt>. If this is provided, <tt>:description</tt> and <tt>money</tt> will be ignored.
78
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
79
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
80
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
81
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
82
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
83
+ #
84
+ # ==== Examples
85
+ # response = gateway.authorize(1000, creditcard,
86
+ # :order_id => '1212', :address => {...}, :email => 'test@test.com',
87
+ # :order_items => [
88
+ # {:description => 'Line Item 1', :cost => '8.98', :quantity => '6'},
89
+ # {:description => 'Line Item 2', :cost => '6.99', :quantity => '4'}
90
+ # ],
91
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
92
+ # :send_customer_email => true,
93
+ # :send_merchant_email => true,
94
+ # :email_text => ['line1', 'line2', 'line3'],
95
+ # :test_mode => true
96
+ # )
97
+ #
98
+ def authorize(money, payment_source, options = {})
99
+ payload = Nokogiri::XML::Builder.new do |xml|
100
+ xml.AuthTransaction {
101
+ xml.Preauth
102
+ add_customer_data(xml, payment_source, options)
103
+ add_invoice(xml, money, options)
104
+ add_payment_source(xml, payment_source)
105
+ add_transaction_control(xml, options)
106
+ add_vendor_data(xml, options)
107
+ }
108
+ end.doc
109
+
110
+ commit(payload)
111
+ end
112
+
113
+ # Performs an authorize and capture in single transaction. In PaymentClearing's
114
+ # documentation this is known as an "Auth" or a "Sale" transaction
115
+ #
116
+ # ==== Parameters
117
+ # * <tt>money</tt> - The amount to be captured. Should be <tt>nil</tt> or an Integer amount in cents.
118
+ # * <tt>creditcard</tt> - The CreditCard details for the transaction
119
+ # * <tt>options</tt> - A Hash of options
120
+ #
121
+ # ==== Options Hash
122
+ # The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
123
+ # * <tt>:order_items</tt> - An Array of Hash objects with the keys <tt>:description</tt>, <tt>:cost</tt> (in cents!), and <tt>:quantity</tt>. If this is provided, <tt>:description</tt> and <tt>money</tt> will be ignored.
124
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
125
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
126
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
127
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
128
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
129
+ #
130
+ # ==== Examples
131
+ # response = gateway.purchase(1000, creditcard,
132
+ # :order_id => '1212', :address => {...}, :email => 'test@test.com',
133
+ # :order_items => [
134
+ # {:description => 'Line Item 1', :cost => '8.98', :quantity => '6'},
135
+ # {:description => 'Line Item 2', :cost => '6.99', :quantity => '4'}
136
+ # ],
137
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
138
+ # :send_customer_email => true,
139
+ # :send_merchant_email => true,
140
+ # :email_text => ['line1', 'line2', 'line3'],
141
+ # :test_mode => true
142
+ # )
143
+ #
144
+ def purchase(money, payment_source, options = {})
145
+ payload = Nokogiri::XML::Builder.new do |xml|
146
+ xml.AuthTransaction {
147
+ add_customer_data(xml, payment_source, options)
148
+ add_invoice(xml, money, options)
149
+ add_payment_source(xml, payment_source)
150
+ add_transaction_control(xml, options)
151
+ add_vendor_data(xml, options)
152
+ }
153
+ end.doc
154
+
155
+ commit(payload)
156
+ end
157
+
158
+ # Captures the funds from an authorize transaction. In PaymentClearing's
159
+ # documentation this is known as a "PostAuth" transaction.
160
+ #
161
+ # ==== Parameters
162
+ # * <tt>money</tt> - The amount to be captured. Should be an Integer amount in cents
163
+ # * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
164
+ # * <tt>options</tt> - A Hash of options, all are optional.
165
+ #
166
+ # ==== Options Hash
167
+ # The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
168
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
169
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
170
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
171
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
172
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
173
+ #
174
+ # ==== Examples
175
+ # response = gateway.capture(1000, creditcard,
176
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
177
+ # :send_customer_email => true,
178
+ # :send_merchant_email => true,
179
+ # :email_text => ['line1', 'line2', 'line3'],
180
+ # :test_mode => true
181
+ # )
182
+ #
183
+ def capture(money, authorization, options = {})
184
+ payload = Nokogiri::XML::Builder.new do |xml|
185
+ xml.PostAuthTransaction {
186
+ xml.OperationXID(authorization)
187
+ add_invoice(xml, money, options)
188
+ add_transaction_control(xml, options)
189
+ add_vendor_data(xml, options)
190
+ }
191
+ end.doc
192
+
193
+ commit(payload)
194
+ end
195
+
196
+ # This will reverse a previously run transaction which *has* *not* settled.
197
+ #
198
+ # ==== Parameters
199
+ # * <tt>money</tt> - This parameter is ignored -- the PaymentClearing gateway does not allow partial voids.
200
+ # * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
201
+ # * <tt>options</tt> - A Hash of options, all are optional
202
+ #
203
+ # ==== Options Hash
204
+ # The standard options (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address) are ignored.
205
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
206
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
207
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
208
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
209
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
210
+ #
211
+ # ==== Examples
212
+ # response = gateway.void(nil, '9999999999',
213
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
214
+ # :send_customer_email => true,
215
+ # :send_merchant_email => true,
216
+ # :email_text => ['line1', 'line2', 'line3'],
217
+ # :test_mode => true
218
+ # )
219
+ #
220
+ def void(money, authorization, options = {})
221
+ payload = Nokogiri::XML::Builder.new do |xml|
222
+ xml.VoidTransaction {
223
+ xml.OperationXID(authorization)
224
+ add_transaction_control(xml, options)
225
+ add_vendor_data(xml, options)
226
+ }
227
+ end.doc
228
+
229
+ commit(payload)
230
+ end
231
+
232
+ # This will reverse a previously run transaction which *has* settled.
233
+ #
234
+ # ==== Parameters
235
+ # * <tt>money</tt> - The amount to be credited. Should be <tt>nil</tt> or an Integer amount in cents
236
+ # * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
237
+ # * <tt>options</tt> - A Hash of options, all are optional
238
+ #
239
+ # ==== Options Hash
240
+ # The standard options (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address) are ignored.
241
+ # * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
242
+ # * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
243
+ # * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
244
+ # * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
245
+ # * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
246
+ #
247
+ # ==== Examples
248
+ # response = gateway.credit(nil, '9999999999',
249
+ # :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
250
+ # :send_customer_email => true,
251
+ # :send_merchant_email => true,
252
+ # :email_text => ['line1', 'line2', 'line3'],
253
+ # :test_mode => true
254
+ # )
255
+ #
256
+ def credit(money, authorization, options = {})
257
+ payload = Nokogiri::XML::Builder.new do |xml|
258
+ xml.TranCreditTransaction {
259
+ xml.OperationXID(authorization)
260
+ add_invoice(xml, money, options)
261
+ add_transaction_control(xml, options)
262
+ add_vendor_data(xml, options)
263
+ }
264
+ end.doc
265
+
266
+ commit(payload)
267
+ end
268
+
269
+ private
270
+
271
+ def add_customer_data(xml, payment_source, options)
272
+ billing_address = options[:billing_address] || options[:address]
273
+ shipping_address = options[:shipping_address] || options[:address]
274
+
275
+ xml.CustomerData {
276
+ xml.Email(options[:email]) unless options[:email].blank?
277
+ xml.CustId(options[:order_id]) unless options[:order_id].blank?
278
+ xml.BillingAddress {
279
+ xml.FirstName(payment_source.first_name || parse_first_name(billing_address[:name]))
280
+ xml.LastName(payment_source.last_name || parse_last_name(billing_address[:name]))
281
+ xml.Address1(billing_address[:address1])
282
+ xml.Address2(billing_address[:address2]) unless billing_address[:address2].blank?
283
+ xml.City(billing_address[:city])
284
+ xml.State(billing_address[:state])
285
+ xml.Zip(billing_address[:zip])
286
+ xml.Country(billing_address[:country])
287
+ xml.Phone(billing_address[:phone])
288
+ }
289
+ xml.ShippingAddress {
290
+ xml.FirstName(payment_source.first_name || parse_first_name(shipping_address[:name]))
291
+ xml.LastName(payment_source.last_name || parse_last_name(shipping_address[:name]))
292
+ xml.Address1(shipping_address[:address1])
293
+ xml.Address2(shipping_address[:address2]) unless shipping_address[:address2].blank?
294
+ xml.City(shipping_address[:city])
295
+ xml.State(shipping_address[:state])
296
+ xml.Zip(shipping_address[:zip])
297
+ xml.Country(shipping_address[:country])
298
+ xml.Phone(shipping_address[:phone])
299
+ } unless shipping_address.blank?
300
+ }
301
+ end
302
+
303
+ def add_invoice(xml, money, options)
304
+ xml.AuthCode options[:force] if options[:force]
305
+ if options[:order_items].blank?
306
+ xml.Total(amount(money)) unless(money.nil? || money < 0.01)
307
+ xml.Description(options[:description]) unless( options[:description].blank?)
308
+ else
309
+ xml.OrderItems {
310
+ options[:order_items].each do |item|
311
+ xml.Item {
312
+ xml.Description(item[:description])
313
+ xml.Cost(amount(item[:cost]))
314
+ xml.Qty(item[:quantity].to_s)
315
+ }
316
+ end
317
+ }
318
+ end
319
+ end
320
+
321
+ def add_payment_source(xml, source)
322
+ case determine_funding_source(source)
323
+ when :credit_card then add_creditcard(xml, source)
324
+ when :check then add_check(xml, source)
325
+ end
326
+ end
327
+
328
+ def determine_funding_source(payment_source)
329
+ case payment_source
330
+ when ActiveMerchant::Billing::CreditCard
331
+ :credit_card
332
+ when ActiveMerchant::Billing::Check
333
+ :check
334
+ end
335
+ end
336
+
337
+ def add_creditcard(xml, creditcard)
338
+ xml.AccountInfo {
339
+ xml.CardAccount {
340
+ xml.AccountNumber(creditcard.number.to_s)
341
+ xml.ExpirationMonth(creditcard.month.to_s.rjust(2,'0'))
342
+ xml.ExpirationYear(creditcard.year.to_s)
343
+ xml.CVVNumber(creditcard.verification_value.to_s) unless creditcard.verification_value.blank?
344
+ }
345
+ }
346
+ end
347
+
348
+ def add_check(xml, check)
349
+ xml.AccountInfo {
350
+ xml.ABA(check.routing_number.to_s)
351
+ xml.AccountNumber(check.account_number.to_s)
352
+ xml.AccountSource(check.account_type.to_s)
353
+ xml.AccountType(check.account_holder_type.to_s)
354
+ xml.CheckNumber(check.number.to_s)
355
+ }
356
+ end
357
+
358
+ def add_transaction_control(xml, options)
359
+ xml.TransactionControl {
360
+ # if there was a 'global' option set...
361
+ xml.TestMode(@options[:test_mode].upcase) if !@options[:test_mode].blank?
362
+ # allow the global option to be overridden...
363
+ xml.TestMode(options[:test_mode].upcase) if !options[:test_mode].blank?
364
+ xml.SendCustomerEmail(options[:send_customer_email].upcase) unless options[:send_customer_email].blank?
365
+ xml.SendMerchantEmail(options[:send_merchant_email].upcase) unless options[:send_merchant_email].blank?
366
+ xml.EmailText {
367
+ options[:email_text].each do |item|
368
+ xml.EmailTextItem(item)
369
+ end
370
+ } if options[:email_text]
371
+ }
372
+ end
373
+
374
+ def add_vendor_data(xml, options)
375
+ return if options[:vendor_data].blank?
376
+ xml.VendorData {
377
+ options[:vendor_data].each do |k,v|
378
+ xml.Element {
379
+ xml.Name(k)
380
+ xml.Key(v)
381
+ }
382
+ end
383
+ }
384
+ end
385
+
386
+ def commit(payload)
387
+ # Set the Content-Type header -- otherwise the URL decoding messes up
388
+ # the Base64 encoded payload signature!
389
+ response = parse(ssl_post(URL, post_data(payload), 'Content-Type' => 'text/xml'))
390
+
391
+ Response.new(successful?(response), response[:error_message], response,
392
+ :test => test?,
393
+ :authorization => response[:xid],
394
+ :avs_result => { :code => response[:avs_response] },
395
+ :cvv_result => response[:cvv_response])
396
+ end
397
+
398
+ def post_data(payload)
399
+ payload_xml = payload.root.to_xml(:indent => 0)
400
+
401
+ payload_signature = sign_payload(payload_xml)
402
+
403
+ request = Nokogiri::XML::Builder.new do |xml|
404
+ xml.GatewayInterface {
405
+ xml.APICredentials {
406
+ xml.Username(@options[:login])
407
+ xml.PayloadSignature(payload_signature)
408
+ xml.TargetGateway(@options[:gateway_id])
409
+ }
410
+ }
411
+ end.doc
412
+
413
+ request.root.children.first.after payload.root
414
+ request.to_xml(:indent => 0)
415
+ end
416
+
417
+ def parse(raw_xml)
418
+ doc = REXML::Document.new(raw_xml)
419
+ response = Hash.new
420
+ transaction_result = doc.root.get_elements('TransactionResponse/TransactionResult/*')
421
+ transaction_result.each do |e|
422
+ response[e.name.to_s.underscore.to_sym] = e.text unless e.text.blank?
423
+ end
424
+ response
425
+ end
426
+
427
+ def successful?(response)
428
+ # Turns out the PaymentClearing gateway is not consistent...
429
+ response[:status].downcase =='ok'
430
+ end
431
+
432
+ def test_mode?(response)
433
+ # The '1' is a legacy thing; most of the time it should be 'TRUE'...
434
+ response[:test_mode] == 'TRUE' || response[:test_mode] == '1'
435
+ end
436
+
437
+ def message_from(response)
438
+ response[:error_message]
439
+ end
440
+
441
+ def sign_payload(payload)
442
+ key = @options[:password].to_s
443
+ digest=OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new(key), key, payload)
444
+ signature = Base64.encode64(digest)
445
+ signature.chomp!
446
+ end
447
+ end
448
+ end
449
+ end
450
+