activemerchant 1.29.1 → 1.31.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 (53) hide show
  1. data/CHANGELOG +58 -0
  2. data/CONTRIBUTORS +27 -0
  3. data/README.md +45 -41
  4. data/lib/active_merchant/billing/check.rb +11 -11
  5. data/lib/active_merchant/billing/credit_card.rb +1 -1
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
  7. data/lib/active_merchant/billing/gateway.rb +2 -2
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +9 -1
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +15 -4
  10. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  11. data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
  12. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +6 -2
  13. data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +5 -2
  15. data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
  16. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  17. data/lib/active_merchant/billing/gateways/eway.rb +114 -171
  18. data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
  19. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +232 -0
  20. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
  21. data/lib/active_merchant/billing/gateways/litle.rb +50 -19
  22. data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
  23. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
  24. data/lib/active_merchant/billing/gateways/moneris.rb +3 -5
  25. data/lib/active_merchant/billing/gateways/moneris_us.rb +1 -1
  26. data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
  27. data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
  28. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  29. data/lib/active_merchant/billing/gateways/ogone.rb +6 -4
  30. data/lib/active_merchant/billing/gateways/optimal_payment.rb +18 -3
  31. data/lib/active_merchant/billing/gateways/orbital.rb +9 -5
  32. data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
  33. data/lib/active_merchant/billing/gateways/paymill.rb +161 -0
  34. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  35. data/lib/active_merchant/billing/gateways/paypal_express.rb +17 -11
  36. data/lib/active_merchant/billing/gateways/pin.rb +157 -0
  37. data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
  38. data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
  39. data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -0
  40. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/spreedly_core.rb +235 -0
  42. data/lib/active_merchant/billing/gateways/stripe.rb +1 -0
  43. data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
  44. data/lib/active_merchant/billing/gateways/worldpay.rb +19 -5
  45. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +4 -1
  46. data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
  47. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
  48. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +14 -14
  49. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +2 -2
  50. data/lib/active_merchant/version.rb +1 -1
  51. data.tar.gz.sig +0 -0
  52. metadata +32 -24
  53. metadata.gz.sig +0 -0
@@ -22,7 +22,7 @@ module ActiveMerchant #:nodoc:
22
22
  # password is your API Token
23
23
  def initialize(options = {})
24
24
  requires!(options, :login, :password)
25
- @options = { :crypt_type => 7 }.update(options)
25
+ options = { :crypt_type => 7 }.merge(options)
26
26
  super
27
27
  end
28
28
 
@@ -70,15 +70,13 @@ module ActiveMerchant #:nodoc:
70
70
  commit 'completion', crediting_params(authorization, :comp_amount => amount(money))
71
71
  end
72
72
 
73
- # Voiding requires the original transaction ID and order ID of some open
74
- # transaction. Closed transactions must be refunded. Note that the only
75
- # methods which may be voided are +capture+ and +purchase+.
73
+ # Voiding cancels an open authorization.
76
74
  #
77
75
  # Concatenate your transaction number and order_id by using a semicolon
78
76
  # (';'). This is to keep the Moneris interface consistent with other
79
77
  # gateways. (See +capture+ for details.)
80
78
  def void(authorization, options = {})
81
- commit 'purchasecorrection', crediting_params(authorization)
79
+ capture(0, authorization, options)
82
80
  end
83
81
 
84
82
  # Performs a refund. This method requires that the original transaction
@@ -22,7 +22,7 @@ module ActiveMerchant #:nodoc:
22
22
  # password is your API Token
23
23
  def initialize(options = {})
24
24
  requires!(options, :login, :password)
25
- @options = { :crypt_type => 7 }.update(options)
25
+ options = { :crypt_type => 7 }.merge(options)
26
26
  super
27
27
  end
28
28
 
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
34
34
  #Transactions currently accepted by NAB Transact XML API
35
35
  TRANSACTIONS = {
36
36
  :purchase => 0, #Standard Payment
37
- :credit => 4, #Refund
37
+ :refund => 4, #Refund
38
38
  :void => 6, #Client Reversal (Void)
39
39
  :authorization => 10, #Preauthorise
40
40
  :capture => 11 #Preauthorise Complete (Advice)
@@ -66,6 +66,10 @@ module ActiveMerchant #:nodoc:
66
66
  end
67
67
  end
68
68
 
69
+ def refund(money, authorization, options = {})
70
+ commit :refund, build_reference_request(money, authorization)
71
+ end
72
+
69
73
  def store(creditcard, options = {})
70
74
  requires!(options, :billing_id, :amount)
71
75
  commit_periodic(build_periodic_item(:addcrn, options[:amount], creditcard, options))
@@ -104,10 +108,23 @@ module ActiveMerchant #:nodoc:
104
108
  xml.target!
105
109
  end
106
110
 
111
+ def build_reference_request(money, reference)
112
+ xml = Builder::XmlMarkup.new
113
+
114
+ transaction_id, order_id, preauth_id, original_amount = reference.split('*')
115
+
116
+ xml.tag! 'amount', (money ? amount(money) : original_amount)
117
+ xml.tag! 'currency', options[:currency] || currency(money)
118
+ xml.tag! 'txnID', transaction_id
119
+ xml.tag! 'purchaseOrderNo', order_id
120
+ xml.tag! 'preauthID', preauth_id
121
+
122
+ xml.target!
123
+ end
124
+
107
125
  #Generate payment request XML
108
126
  # - API is set to allow multiple Txn's but currentlu only allows one
109
127
  # - txnSource = 23 - (XML)
110
-
111
128
  def build_request(action, body)
112
129
  xml = Builder::XmlMarkup.new
113
130
  xml.instruct!
@@ -210,7 +227,7 @@ module ActiveMerchant #:nodoc:
210
227
  end
211
228
 
212
229
  def authorization_from(response)
213
- response[:txn_id]
230
+ [response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
214
231
  end
215
232
 
216
233
  def message_from(response)
@@ -177,6 +177,7 @@ module ActiveMerchant #:nodoc:
177
177
 
178
178
  def post_data(action, parameters = {})
179
179
  parameters[:account_id] = @options[:login]
180
+ parameters[:site_tag] = @options[:site_tag] if @options[:site_tag].present?
180
181
  parameters[:pay_type] = 'C'
181
182
  parameters[:tran_type] = TRANSACTIONS[action]
182
183
 
@@ -0,0 +1,223 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ #
4
+ # NETPAY Gateway
5
+ #
6
+ # Support for NETPAY's HTTP Connector payment gateway in Mexico.
7
+ #
8
+ # The gateway sends requests as HTTP POST and receives the response details
9
+ # in the HTTP header, making the process really rather simple.
10
+ #
11
+ # Support for calls to the authorize and capture methods have been included
12
+ # as per the Netpay manuals, however, your millage may vary with these
13
+ # methods. At the time of writing (January 2013) they were not fully
14
+ # supported by the production or test gateways. This situation is
15
+ # expected to change within a few weeks/months.
16
+ #
17
+ # Purchases can be cancelled (`#void`) only within 24 hours of the
18
+ # transaction. After this, a refund should be performed instead.
19
+ #
20
+ # In addition to the regular ActiveMerchant transaction options, NETPAY
21
+ # also supports a `:mode` parameter. This allows testing to be peformed
22
+ # in production and force specific results.
23
+ #
24
+ # * 'P' - Production
25
+ # * 'A' - Approved
26
+ # * 'D' - Declined
27
+ # * 'R' - Random (Approved or Declined)
28
+ # * 'T' - Test
29
+ #
30
+ # For example:
31
+ #
32
+ # response = @gateway.purchase(1000, card, :mode => 'D')
33
+ # response.success # false
34
+ #
35
+ class NetpayGateway < Gateway
36
+ self.test_url = 'http://200.57.87.243:8855'
37
+ self.live_url = 'https://suite.netpay.com.mx/acquirerprd'
38
+
39
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
40
+ self.supported_countries = ['MX']
41
+
42
+ self.default_currency = 'MXN'
43
+
44
+ # The card types supported by the payment gateway
45
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
46
+
47
+ # The homepage URL of the gateway
48
+ self.homepage_url = 'http://www.netpay.com.mx'
49
+
50
+ # The name of the gateway
51
+ self.display_name = 'NETPAY Gateway'
52
+
53
+ CURRENCY_CODES = {
54
+ "MXN" => '484'
55
+ }
56
+
57
+ # The header keys that we will provide in the response params hash
58
+ RESPONSE_KEYS = ['ResponseMsg', 'ResponseText', 'ResponseCode', 'TimeIn', 'TimeOut', 'AuthCode', 'OrderId', 'CardTypeName', 'MerchantId', 'IssuerAuthDate']
59
+
60
+ def initialize(options = {})
61
+ requires!(options, :store_id, :login, :password)
62
+ super
63
+ end
64
+
65
+ # Send an authorization request
66
+ def authorize(money, creditcard, options = {})
67
+ post = {}
68
+ add_invoice(post, options)
69
+ add_creditcard(post, creditcard)
70
+ add_customer_data(post, options)
71
+ add_amount(post, money, options)
72
+
73
+ commit('PreAuth', post, options)
74
+ end
75
+
76
+ # Capture an authorization
77
+ def capture(money, authorization, options = {})
78
+ post = {}
79
+ add_order_id(post, order_id_from(authorization))
80
+ add_amount(post, money, options)
81
+
82
+ commit('PostAuth', post, options)
83
+ end
84
+
85
+ # Cancel an auth/purchase within first 24 hours
86
+ def void(authorization, options = {})
87
+ post = {}
88
+ order_id, amount, currency = split_authorization(authorization)
89
+ add_order_id(post, order_id)
90
+ post['Total'] = (options[:amount] || amount)
91
+ post['CurrencyCode'] = currency
92
+
93
+ commit('Refund', post, options)
94
+ end
95
+
96
+ # Make a purchase.
97
+ def purchase(money, creditcard, options = {})
98
+ post = {}
99
+ add_invoice(post, options)
100
+ add_creditcard(post, creditcard)
101
+ add_customer_data(post, options)
102
+ add_amount(post, money, options)
103
+
104
+ commit('Auth', post, options)
105
+ end
106
+
107
+ # Perform a Credit transaction.
108
+ def refund(money, authorization, options = {})
109
+ post = {}
110
+ add_order_id(post, order_id_from(authorization))
111
+ add_amount(post, money, options)
112
+
113
+ #commit('Refund', post, options)
114
+ commit('Credit', post, options)
115
+ end
116
+
117
+ private
118
+
119
+ def add_login_data(post)
120
+ post['StoreId'] = @options[:store_id]
121
+ post['UserName'] = @options[:login]
122
+ post['Password'] = @options[:password]
123
+ end
124
+
125
+ def add_action(post, action, options)
126
+ post['ResourceName'] = action
127
+ post['ContentType'] = 'Transaction'
128
+ post['Mode'] = options[:mode] || 'P'
129
+ end
130
+
131
+ def add_order_id(post, order_id)
132
+ post['OrderId'] = order_id
133
+ end
134
+
135
+ def add_amount(post, money, options)
136
+ post['Total'] = amount(money)
137
+ post['CurrencyCode'] = currency_code(options[:currency] || currency(money))
138
+ end
139
+
140
+ def add_customer_data(post, options)
141
+ post['IPAddress'] = options[:ip] unless options[:ip].blank?
142
+ end
143
+
144
+ def add_invoice(post, options)
145
+ post['Comments'] = options[:description] if options[:description]
146
+ end
147
+
148
+ def add_creditcard(post, creditcard)
149
+ post['CardNumber'] = creditcard.number
150
+ post['ExpDate'] = expdate(creditcard)
151
+ post['CustomerName'] = creditcard.name
152
+ post['CVV2'] = creditcard.verification_value unless creditcard.verification_value.nil?
153
+ end
154
+
155
+ def build_authorization(request_params, response_params)
156
+ [response_params['OrderId'], request_params['Total'], request_params['CurrencyCode']].join('|')
157
+ end
158
+
159
+ def split_authorization(authorization)
160
+ order_id, amount, currency = authorization.split("|")
161
+ [order_id, amount, currency]
162
+ end
163
+
164
+ def order_id_from(authorization)
165
+ split_authorization(authorization).first
166
+ end
167
+
168
+ def expdate(credit_card)
169
+ year = sprintf("%.4i", credit_card.year)
170
+ month = sprintf("%.2i", credit_card.month)
171
+
172
+ "#{month}/#{year[-2..-1]}"
173
+ end
174
+
175
+ def url
176
+ test? ? test_url : live_url
177
+ end
178
+
179
+ def parse(response, request_params)
180
+ response_params = params_from_response(response)
181
+
182
+ success = (response_params['ResponseCode'] == '00')
183
+ message = response_params['ResponseText'] || response_params['ResponseMsg']
184
+ options = @options.merge(:test => test?,
185
+ :authorization => build_authorization(request_params, response_params))
186
+
187
+ Response.new(success, message, response_params, options)
188
+ end
189
+
190
+ def commit(action, parameters, options)
191
+ add_login_data(parameters)
192
+ add_action(parameters, action, options)
193
+
194
+ post = parameters.collect{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
195
+ parse(ssl_post(url, post), parameters)
196
+ end
197
+
198
+ # Override the regular handle response so we can access the headers
199
+ def handle_response(response)
200
+ case response.code.to_i
201
+ when 200...300
202
+ response
203
+ else
204
+ raise ResponseError.new(response)
205
+ end
206
+ end
207
+
208
+ # Return a hash containing all the useful, or informative values from netpay
209
+ def params_from_response(response)
210
+ params = {}
211
+ RESPONSE_KEYS.each do |k|
212
+ params[k] = response[k] unless response[k].to_s.empty?
213
+ end
214
+ params
215
+ end
216
+
217
+ def currency_code(currency)
218
+ return currency if currency =~ /^\d+$/
219
+ CURRENCY_CODES[currency]
220
+ end
221
+ end
222
+ end
223
+ end
@@ -154,23 +154,25 @@ module ActiveMerchant #:nodoc:
154
154
 
155
155
  # Verify and transfer the specified amount.
156
156
  def purchase(money, payment_source, options = {})
157
- post = {}
157
+ post = {}
158
+ action = options[:action] || 'SAL'
158
159
  add_invoice(post, options)
159
160
  add_payment_source(post, payment_source, options)
160
161
  add_address(post, payment_source, options)
161
162
  add_customer_data(post, options)
162
163
  add_money(post, money, options)
163
- commit('SAL', post)
164
+ commit(action, post)
164
165
  end
165
166
 
166
167
  # Complete a previously authorized transaction.
167
168
  def capture(money, authorization, options = {})
168
- post = {}
169
+ post = {}
170
+ action = options[:action] || 'SAL'
169
171
  add_authorization(post, reference_from(authorization))
170
172
  add_invoice(post, options)
171
173
  add_customer_data(post, options)
172
174
  add_money(post, money, options)
173
- commit('SAL', post)
175
+ commit(action, post)
174
176
  end
175
177
 
176
178
  # Cancels a previously authorized transaction.
@@ -90,7 +90,9 @@ module ActiveMerchant #:nodoc:
90
90
 
91
91
  Response.new(successful?(response), message_from(response), hash_from_xml(response),
92
92
  :test => test?,
93
- :authorization => authorization_from(response)
93
+ :authorization => authorization_from(response),
94
+ :avs_result => { :code => avs_result_from(response) },
95
+ :cvv_result => cvv_result_from(response)
94
96
  )
95
97
  end
96
98
 
@@ -108,7 +110,15 @@ module ActiveMerchant #:nodoc:
108
110
  end
109
111
 
110
112
  def authorization_from(response)
111
- REXML::XPath.first(response, '//confirmationNumber').text rescue nil
113
+ get_text_from_document(response, '//confirmationNumber')
114
+ end
115
+
116
+ def avs_result_from(response)
117
+ get_text_from_document(response, '//avsResponse')
118
+ end
119
+
120
+ def cvv_result_from(response)
121
+ get_text_from_document(response, '//cvdResponse')
112
122
  end
113
123
 
114
124
  def hash_from_xml(response)
@@ -138,6 +148,11 @@ module ActiveMerchant #:nodoc:
138
148
  xml.target!
139
149
  end
140
150
 
151
+ def get_text_from_document(document, node)
152
+ node = REXML::XPath.first(document, node)
153
+ node && node.text
154
+ end
155
+
141
156
  def cc_auth_request(money, opts)
142
157
  xml_document('ccAuthRequestV1') do |xml|
143
158
  build_merchant_account(xml, @options)
@@ -251,7 +266,7 @@ module ActiveMerchant #:nodoc:
251
266
  xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
252
267
  xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
253
268
  xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
254
- #xml.tag! 'email' , ''
269
+ xml.tag! 'email', CGI.escape(opts[:email]) if opts[:email]
255
270
  end
256
271
  end
257
272
 
@@ -125,9 +125,13 @@ module ActiveMerchant #:nodoc:
125
125
  refund(money, authorization, options)
126
126
  end
127
127
 
128
- # setting money to nil will perform a full void
129
- def void(money, authorization, options = {})
130
- order = build_void_request_xml(money, authorization, options)
128
+ def void(authorization, options = {}, deprecated = {})
129
+ if(!options.kind_of?(Hash))
130
+ deprecated("Calling the void method with an amount parameter is deprecated and will be removed in a future version.")
131
+ return void(options, deprecated.merge(:amount => authorization))
132
+ end
133
+
134
+ order = build_void_request_xml(authorization, options)
131
135
  commit(order, :void)
132
136
  end
133
137
 
@@ -396,7 +400,7 @@ module ActiveMerchant #:nodoc:
396
400
  xml.target!
397
401
  end
398
402
 
399
- def build_void_request_xml(money, authorization, parameters = {})
403
+ def build_void_request_xml(authorization, parameters = {})
400
404
  tx_ref_num, order_id = split_authorization(authorization)
401
405
  xml = xml_envelope
402
406
  xml.tag! :Request do
@@ -404,7 +408,7 @@ module ActiveMerchant #:nodoc:
404
408
  add_xml_credentials(xml)
405
409
  xml.tag! :TxRefNum, tx_ref_num
406
410
  xml.tag! :TxRefIdx, parameters[:transaction_index]
407
- xml.tag! :AdjustedAmt, amount(money)
411
+ xml.tag! :AdjustedAmt, parameters[:amount] # setting adjusted amount to nil will void entire amount
408
412
  xml.tag! :OrderID, format_order_id(order_id || parameters[:order_id])
409
413
  add_bin_merchant_and_terminal(xml, parameters)
410
414
  end
@@ -140,6 +140,7 @@ module ActiveMerchant #:nodoc:
140
140
  add_amount(result, money, options)
141
141
  add_invoice(result, options)
142
142
  add_address_verification_data(result, options)
143
+ add_optional_elements(result, options)
143
144
  result
144
145
  end
145
146
 
@@ -149,6 +150,7 @@ module ActiveMerchant #:nodoc:
149
150
  add_amount(result, money, options)
150
151
  add_invoice(result, options)
151
152
  add_reference(result, identification)
153
+ add_optional_elements(result, options)
152
154
  result
153
155
  end
154
156
 
@@ -157,6 +159,7 @@ module ActiveMerchant #:nodoc:
157
159
  add_credit_card(result, credit_card)
158
160
  add_amount(result, 100, options) #need to make an auth request for $1
159
161
  add_token_request(result, options)
162
+ add_optional_elements(result, options)
160
163
  result
161
164
  end
162
165
 
@@ -209,7 +212,7 @@ module ActiveMerchant #:nodoc:
209
212
 
210
213
  def add_invoice(xml, options)
211
214
  xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
212
- xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
215
+ xml.add_element("MerchantReference").text = options[:description].to_s.slice(0, 50) unless options[:description].blank?
213
216
  end
214
217
 
215
218
  def add_address_verification_data(xml, options)
@@ -223,6 +226,52 @@ module ActiveMerchant #:nodoc:
223
226
  xml.add_element("AvsPostCode").text = address[:zip]
224
227
  end
225
228
 
229
+ # The options hash may contain optional data which will be passed
230
+ # through the the specialized optional fields at PaymentExpress
231
+ # as follows:
232
+ #
233
+ # {
234
+ # :client_type => :web, # Possible values are: :web, :ivr, :moto, :unattended, :internet, or :recurring
235
+ # :txn_data1 => "String up to 255 characters",
236
+ # :txn_data2 => "String up to 255 characters",
237
+ # :txn_data3 => "String up to 255 characters"
238
+ # }
239
+ #
240
+ # +:client_type+, while not documented for PxPost, will be sent as
241
+ # the +ClientType+ XML element as described in the documentation for
242
+ # the PaymentExpress WebService: http://www.paymentexpress.com/Technical_Resources/Ecommerce_NonHosted/WebService#clientType
243
+ # (PaymentExpress have confirmed that this value works the same in PxPost).
244
+ # The value sent for +:client_type+ will be normalized and sent
245
+ # as one of the explicit values allowed by PxPost:
246
+ #
247
+ # :web => "Web"
248
+ # :ivr => "IVR"
249
+ # :moto => "MOTO"
250
+ # :unattended => "Unattended"
251
+ # :internet => "Internet"
252
+ # :recurring => "Recurring"
253
+ #
254
+ # If you set the +:client_type+ to any value not listed above,
255
+ # the ClientType element WILL NOT BE INCLUDED at all in the
256
+ # POST data.
257
+ #
258
+ # +:txn_data1+, +:txn_data2+, and +:txn_data3+ will be sent as
259
+ # +TxnData1+, +TxnData2+, and +TxnData3+, respectively, and are
260
+ # free form fields of the merchant's choosing, as documented here:
261
+ # http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#txndata
262
+ #
263
+ # These optional elements are added to all transaction types:
264
+ # +purchase+, +authorize+, +capture+, +refund+, +store+
265
+ def add_optional_elements(xml, options)
266
+ if client_type = normalized_client_type(options[:client_type])
267
+ xml.add_element("ClientType").text = client_type
268
+ end
269
+
270
+ xml.add_element("TxnData1").text = options[:txn_data1].to_s.slice(0,255) unless options[:txn_data1].blank?
271
+ xml.add_element("TxnData2").text = options[:txn_data2].to_s.slice(0,255) unless options[:txn_data2].blank?
272
+ xml.add_element("TxnData3").text = options[:txn_data3].to_s.slice(0,255) unless options[:txn_data3].blank?
273
+ end
274
+
226
275
  def new_transaction
227
276
  REXML::Document.new.add_element("Txn")
228
277
  end
@@ -266,6 +315,18 @@ module ActiveMerchant #:nodoc:
266
315
  def format_date(month, year)
267
316
  "#{format(month, :two_digits)}#{format(year, :two_digits)}"
268
317
  end
318
+
319
+ def normalized_client_type(client_type_from_options)
320
+ case client_type_from_options.to_s.downcase
321
+ when 'web' then "Web"
322
+ when 'ivr' then "IVR"
323
+ when 'moto' then "MOTO"
324
+ when 'unattended' then "Unattended"
325
+ when 'internet' then "Internet"
326
+ when 'recurring' then "Recurring"
327
+ else nil
328
+ end
329
+ end
269
330
  end
270
331
 
271
332
  class PaymentExpressResponse < Response