activemerchant 1.44.1 → 1.45.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 (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -3
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG +48 -0
  5. data/CONTRIBUTORS +12 -0
  6. data/README.md +15 -5
  7. data/lib/active_merchant/billing.rb +2 -0
  8. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  9. data/lib/active_merchant/billing/gateway.rb +36 -4
  10. data/lib/active_merchant/billing/gateways/adyen.rb +6 -2
  11. data/lib/active_merchant/billing/gateways/authorize_net.rb +332 -255
  12. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  13. data/lib/active_merchant/billing/gateways/bogus.rb +9 -9
  14. data/lib/active_merchant/billing/gateways/borgun.rb +0 -1
  15. data/lib/active_merchant/billing/gateways/braintree_blue.rb +8 -0
  16. data/lib/active_merchant/billing/gateways/cashnet.rb +17 -10
  17. data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
  18. data/lib/active_merchant/billing/gateways/conekta.rb +1 -1
  19. data/lib/active_merchant/billing/gateways/cyber_source.rb +1 -1
  20. data/lib/active_merchant/billing/gateways/elavon.rb +3 -3
  21. data/lib/active_merchant/billing/gateways/eway_rapid.rb +114 -13
  22. data/lib/active_merchant/billing/gateways/finansbank.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
  24. data/lib/active_merchant/billing/gateways/hps.rb +27 -20
  25. data/lib/active_merchant/billing/gateways/iats_payments.rb +68 -35
  26. data/lib/active_merchant/billing/gateways/litle.rb +36 -1
  27. data/lib/active_merchant/billing/gateways/merchant_one.rb +0 -1
  28. data/lib/active_merchant/billing/gateways/merchant_ware.rb +8 -4
  29. data/lib/active_merchant/billing/gateways/mercury.rb +17 -10
  30. data/lib/active_merchant/billing/gateways/moneris.rb +11 -6
  31. data/lib/active_merchant/billing/gateways/moneris_us.rb +126 -33
  32. data/lib/active_merchant/billing/gateways/money_movers.rb +0 -1
  33. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -1
  34. data/lib/active_merchant/billing/gateways/network_merchants.rb +5 -5
  35. data/lib/active_merchant/billing/gateways/nmi.rb +241 -5
  36. data/lib/active_merchant/billing/gateways/openpay.rb +1 -0
  37. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -1
  38. data/lib/active_merchant/billing/gateways/orbital.rb +6 -4
  39. data/lib/active_merchant/billing/gateways/pay_junction.rb +9 -5
  40. data/lib/active_merchant/billing/gateways/payex.rb +19 -9
  41. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -2
  42. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  43. data/lib/active_merchant/billing/gateways/payscout.rb +0 -2
  44. data/lib/active_merchant/billing/gateways/pin.rb +1 -1
  45. data/lib/active_merchant/billing/gateways/psigate.rb +1 -2
  46. data/lib/active_merchant/billing/gateways/redsys.rb +37 -40
  47. data/lib/active_merchant/billing/gateways/secure_pay.rb +181 -9
  48. data/lib/active_merchant/billing/gateways/stripe.rb +106 -31
  49. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  50. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +38 -10
  51. data/lib/active_merchant/billing/gateways/webpay.rb +14 -0
  52. data/lib/active_merchant/billing/payment_token.rb +21 -0
  53. data/lib/active_merchant/billing/response.rb +2 -1
  54. data/lib/active_merchant/country.rb +6 -1
  55. data/lib/active_merchant/version.rb +1 -1
  56. metadata +8 -3
  57. metadata.gz.sig +0 -0
  58. data/lib/active_merchant/billing/gateways/samurai.rb +0 -130
@@ -18,10 +18,22 @@ module ActiveMerchant #:nodoc:
18
18
  self.homepage_url = 'http://www.monerisusa.com/'
19
19
  self.display_name = 'Moneris (US)'
20
20
 
21
- # login is your Store ID
22
- # password is your API Token
21
+ # Initialize the Gateway
22
+ #
23
+ # The gateway requires that a valid login and password be passed
24
+ # in the +options+ hash.
25
+ #
26
+ # ==== Options
27
+ #
28
+ # * <tt>:login</tt> -- Your Store ID
29
+ # * <tt>:password</tt> -- Your API Token
30
+ # * <tt>:cvv_enabled</tt> -- Specify that you would like the CVV passed to the gateway.
31
+ # Only particular account types at Moneris will allow this.
32
+ # Defaults to false. (optional)
23
33
  def initialize(options = {})
24
34
  requires!(options, :login, :password)
35
+ @cvv_enabled = options[:cvv_enabled]
36
+ @avs_enabled = options[:avs_enabled]
25
37
  options = { :crypt_type => 7 }.merge(options)
26
38
  super
27
39
  end
@@ -31,16 +43,32 @@ module ActiveMerchant #:nodoc:
31
43
  # captured at a later date.
32
44
  #
33
45
  # Pass in +order_id+ and optionally a +customer+ parameter.
34
- def authorize(money, creditcard, options = {})
35
- debit_commit 'us_preauth', money, creditcard, options
46
+ def authorize(money, creditcard_or_datakey, options = {})
47
+ requires!(options, :order_id)
48
+ post = {}
49
+ add_payment_source(post, creditcard_or_datakey, options)
50
+ post[:amount] = amount(money)
51
+ post[:order_id] = options[:order_id]
52
+ post[:address] = options[:billing_address] || options[:address]
53
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
54
+ action = (post[:data_key].blank?) ? 'us_preauth' : 'us_res_preauth_cc'
55
+ commit(action, post)
36
56
  end
37
57
 
38
- # This action verifies funding on a customer's card, and readies them for
58
+ # This action verifies funding on a customer's card and readies them for
39
59
  # deposit in a merchant's account.
40
60
  #
41
61
  # Pass in <tt>order_id</tt> and optionally a <tt>customer</tt> parameter
42
- def purchase(money, creditcard, options = {})
43
- debit_commit 'us_purchase', money, creditcard, options
62
+ def purchase(money, creditcard_or_datakey, options = {})
63
+ requires!(options, :order_id)
64
+ post = {}
65
+ add_payment_source(post, creditcard_or_datakey, options)
66
+ post[:amount] = amount(money)
67
+ post[:order_id] = options[:order_id]
68
+ post[:address] = options[:billing_address] || options[:address]
69
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
70
+ action = (post[:data_key].blank?) ? 'us_purchase' : 'us_res_purchase_cc'
71
+ commit(action, post)
44
72
  end
45
73
 
46
74
  # This method retrieves locked funds from a customer's account (from a
@@ -79,27 +107,45 @@ module ActiveMerchant #:nodoc:
79
107
  commit 'us_refund', crediting_params(authorization, :amount => amount(money))
80
108
  end
81
109
 
110
+ def store(credit_card, options = {})
111
+ post = {}
112
+ post[:pan] = credit_card.number
113
+ post[:expdate] = expdate(credit_card)
114
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
115
+ commit('us_res_add_cc', post)
116
+ end
117
+
118
+ def unstore(data_key, options = {})
119
+ post = {}
120
+ post[:data_key] = data_key
121
+ commit('us_res_delete', post)
122
+ end
123
+
124
+ def update(data_key, credit_card, options = {})
125
+ post = {}
126
+ post[:pan] = credit_card.number
127
+ post[:expdate] = expdate(credit_card)
128
+ post[:data_key] = data_key
129
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
130
+ commit('us_res_update_cc', post)
131
+ end
132
+
82
133
  private # :nodoc: all
83
134
 
84
135
  def expdate(creditcard)
85
136
  sprintf("%.4i", creditcard.year)[-2..-1] + sprintf("%.2i", creditcard.month)
86
137
  end
87
138
 
88
- def debit_commit(commit_type, money, creditcard, options)
89
- requires!(options, :order_id)
90
- commit(commit_type, debit_params(money, creditcard, options))
91
- end
92
-
93
- # Common params used amongst the +purchase+ and +authorization+ methods
94
- def debit_params(money, creditcard, options = {})
95
- {
96
- :order_id => options[:order_id],
97
- :cust_id => options[:customer],
98
- :amount => amount(money),
99
- :pan => creditcard.number,
100
- :expdate => expdate(creditcard),
101
- :crypt_type => options[:crypt_type] || @options[:crypt_type]
102
- }
139
+ def add_payment_source(post, source, options)
140
+ if source.is_a?(String)
141
+ post[:data_key] = source
142
+ post[:cust_id] = options[:customer]
143
+ else
144
+ post[:pan] = source.number
145
+ post[:expdate] = expdate(source)
146
+ post[:cvd_value] = source.verification_value if source.verification_value?
147
+ post[:cust_id] = options[:customer] || source.name
148
+ end
103
149
  end
104
150
 
105
151
  # Common params used amongst the +credit+, +void+ and +capture+ methods
@@ -122,10 +168,15 @@ module ActiveMerchant #:nodoc:
122
168
  end
123
169
 
124
170
  def commit(action, parameters = {})
125
- response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(action, parameters)))
171
+ data = post_data(action, parameters)
172
+ url = test? ? self.test_url : self.live_url
173
+ raw = ssl_post(url, data)
174
+ response = parse(raw)
126
175
 
127
176
  Response.new(successful?(response), message_from(response[:message]), response,
128
177
  :test => test?,
178
+ :avs_result => { :code => response[:avs_result_code] },
179
+ :cvv_result => response[:cvd_result_code] && response[:cvd_result_code][-1,1],
129
180
  :authorization => authorization_from(response)
130
181
  )
131
182
  end
@@ -163,14 +214,49 @@ module ActiveMerchant #:nodoc:
163
214
  root = xml.add_element("request")
164
215
  root.add_element("store_id").text = options[:login]
165
216
  root.add_element("api_token").text = options[:password]
166
- transaction = root.add_element(action)
217
+ root.add_element(transaction_element(action, parameters))
218
+
219
+ xml.to_s
220
+ end
221
+
222
+ def transaction_element(action, parameters)
223
+ transaction = REXML::Element.new(action)
167
224
 
168
225
  # Must add the elements in the correct order
169
226
  actions[action].each do |key|
170
- transaction.add_element(key.to_s).text = parameters[key] unless parameters[key].blank?
227
+ case key
228
+ when :avs_info
229
+ transaction.add_element(avs_element(parameters[:address])) if @avs_enabled && parameters[:address]
230
+ when :cvd_info
231
+ transaction.add_element(cvd_element(parameters[:cvd_value])) if @cvv_enabled
232
+ else
233
+ transaction.add_element(key.to_s).text = parameters[key] unless parameters[key].blank?
234
+ end
171
235
  end
172
236
 
173
- xml.to_s
237
+ transaction
238
+ end
239
+
240
+ def avs_element(address)
241
+ full_address = "#{address[:address1]} #{address[:address2]}"
242
+ tokens = full_address.split(/\s+/)
243
+
244
+ element = REXML::Element.new('avs_info')
245
+ element.add_element('avs_street_number').text = tokens.select{|x| x =~ /\d/}.join(' ')
246
+ element.add_element('avs_street_name').text = tokens.reject{|x| x =~ /\d/}.join(' ')
247
+ element.add_element('avs_zipcode').text = address[:zip]
248
+ element
249
+ end
250
+
251
+ def cvd_element(cvd_value)
252
+ element = REXML::Element.new('cvd_info')
253
+ if cvd_value
254
+ element.add_element('cvd_indicator').text = "1"
255
+ element.add_element('cvd_value').text = cvd_value
256
+ else
257
+ element.add_element('cvd_indicator').text = "0"
258
+ end
259
+ element
174
260
  end
175
261
 
176
262
  def message_from(message)
@@ -180,17 +266,24 @@ module ActiveMerchant #:nodoc:
180
266
 
181
267
  def actions
182
268
  {
183
- "us_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
184
- "us_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
269
+ "us_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info],
270
+ "us_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info],
271
+ "us_command" => [:order_id],
185
272
  "us_refund" => [:order_id, :amount, :txn_number, :crypt_type],
186
- "us_ind_refund" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
273
+ "us_indrefund" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
187
274
  "us_completion" => [:order_id, :comp_amount, :txn_number, :crypt_type],
188
275
  "us_purchasecorrection" => [:order_id, :txn_number, :crypt_type],
189
- "us_cavv_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv],
190
- "us_cavv_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv],
191
- "us_batchcloseall" => [],
276
+ "us_cavvpurcha" => [:order_id, :cust_id, :amount, :pan, :expdate, :cav],
277
+ "us_cavvpreaut" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv],
278
+ "us_transact" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
279
+ "us_Batchcloseall" => [],
192
280
  "us_opentotals" => [:ecr_number],
193
- "us_batchclose" => [:ecr_number]
281
+ "us_batchclose" => [:ecr_number],
282
+ "us_res_add_cc" => [:pan, :expdate, :crypt_type],
283
+ "us_res_delete" => [:data_key],
284
+ "us_res_update_cc" => [:data_key, :pan, :expdate, :crypt_type],
285
+ "us_res_purchase_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type],
286
+ "us_res_preauth_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type]
194
287
  }
195
288
  end
196
289
  end
@@ -9,7 +9,6 @@ module ActiveMerchant #:nodoc:
9
9
  self.display_name = 'MoneyMovers'
10
10
  self.supported_countries = ['US']
11
11
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
- self.ssl_version = :SSLv3
13
12
 
14
13
  def initialize(options = {})
15
14
  requires!(options, :login, :password)
@@ -151,7 +151,12 @@ module ActiveMerchant
151
151
  def post_data(action, params)
152
152
  params['COMMAND'] = TRANSACTIONS[action]
153
153
  params['LOGIN'] = "#{@options[:login]}/#{@options[:password]}"
154
- URI.encode(params.map{|k,v| "#{k}=#{v}"}.join('&'))
154
+ escape_uri(params.map{|k,v| "#{k}=#{v}"}.join('&'))
155
+ end
156
+
157
+ # The upstream is picky and so we can't use CGI.escape like we want to
158
+ def escape_uri(uri)
159
+ URI::DEFAULT_PARSER.escape(uri)
155
160
  end
156
161
 
157
162
  def parse(response)
@@ -60,7 +60,7 @@ module ActiveMerchant #:nodoc:
60
60
  add_address(post, options)
61
61
  add_shipping_address(post, options)
62
62
  add_payment_method(post, creditcard_or_vault_id, options)
63
- add_amount(post, money)
63
+ add_amount(post, money, options)
64
64
  post
65
65
  end
66
66
 
@@ -68,10 +68,10 @@ module ActiveMerchant #:nodoc:
68
68
  build_auth_post(money, creditcard, options)
69
69
  end
70
70
 
71
- def build_capture_post(money, authorization, option)
71
+ def build_capture_post(money, authorization, options)
72
72
  post = {}
73
73
  post[:transactionid] = authorization
74
- add_amount(post, money)
74
+ add_amount(post, money, options)
75
75
  post
76
76
  end
77
77
 
@@ -84,7 +84,7 @@ module ActiveMerchant #:nodoc:
84
84
  def build_refund_post(money, authorization, options)
85
85
  post = {}
86
86
  post[:transactionid] = authorization
87
- add_amount(post, money)
87
+ add_amount(post, money, options)
88
88
  post
89
89
  end
90
90
 
@@ -184,7 +184,7 @@ module ActiveMerchant #:nodoc:
184
184
  post[:password] = @options[:password]
185
185
  end
186
186
 
187
- def add_amount(post, money)
187
+ def add_amount(post, money, options)
188
188
  post[:currency] = options[:currency] || currency(money)
189
189
  post[:amount] = amount(money)
190
190
  end
@@ -1,20 +1,256 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
- class NmiGateway < AuthorizeNetGateway
3
+ class NmiGateway < Gateway
4
+ API_VERSION = '3.1'
5
+
4
6
  self.test_url = 'https://secure.networkmerchants.com/gateway/transact.dll'
5
7
  self.live_url = 'https://secure.networkmerchants.com/gateway/transact.dll'
6
- self.homepage_url = 'http://nmi.com/'
7
- self.display_name = 'NMI'
8
+
9
+ class_attribute :duplicate_window
10
+
11
+ APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
12
+
13
+ RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT, AUTHORIZATION_CODE = 0, 2, 3, 4
14
+ AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE, CARDHOLDER_AUTH_CODE = 5, 6, 38, 39
15
+
16
+ self.default_currency = 'USD'
17
+
8
18
  self.supported_countries = ['US']
9
19
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
20
+ self.homepage_url = 'http://nmi.com/'
21
+ self.display_name = 'NMI'
22
+
23
+ CARD_CODE_ERRORS = %w( N S )
24
+ AVS_ERRORS = %w( A E N R W Z )
25
+ AVS_REASON_CODES = %w(27 45)
26
+ TRANSACTION_ALREADY_ACTIONED = %w(310 311)
27
+
28
+ def initialize(options = {})
29
+ requires!(options, :login, :password)
30
+ super
31
+ end
32
+
33
+ def authorize(money, paysource, options = {})
34
+ post = {}
35
+ add_currency_code(post, money, options)
36
+ add_invoice(post, options)
37
+ add_payment_source(post, paysource, options)
38
+ add_address(post, options)
39
+ add_customer_data(post, options)
40
+ add_duplicate_window(post)
41
+
42
+ commit('AUTH_ONLY', money, post)
43
+ end
44
+
45
+ def purchase(money, paysource, options = {})
46
+ post = {}
47
+ add_currency_code(post, money, options)
48
+ add_invoice(post, options)
49
+ add_payment_source(post, paysource, options)
50
+ add_address(post, options)
51
+ add_customer_data(post, options)
52
+ add_duplicate_window(post)
53
+
54
+ commit('AUTH_CAPTURE', money, post)
55
+ end
56
+
57
+ def capture(money, authorization, options = {})
58
+ post = {:trans_id => authorization}
59
+ add_customer_data(post, options)
60
+ add_invoice(post, options)
61
+ commit('PRIOR_AUTH_CAPTURE', money, post)
62
+ end
63
+
64
+ def void(authorization, options = {})
65
+ post = {:trans_id => authorization}
66
+ add_duplicate_window(post)
67
+ commit('VOID', nil, post)
68
+ end
69
+
70
+ def refund(money, identification, options = {})
71
+ requires!(options, :card_number)
72
+
73
+ post = { :trans_id => identification,
74
+ :card_num => options[:card_number]
75
+ }
76
+
77
+ post[:first_name] = options[:first_name] if options[:first_name]
78
+ post[:last_name] = options[:last_name] if options[:last_name]
79
+ post[:zip] = options[:zip] if options[:zip]
80
+
81
+ add_invoice(post, options)
82
+ add_duplicate_window(post)
83
+
84
+ commit('CREDIT', money, post)
85
+ end
86
+
87
+ def credit(money, identification, options = {})
88
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
89
+ refund(money, identification, options)
90
+ end
91
+
92
+ def verify(credit_card, options = {})
93
+ MultiResponse.run(:use_first_response) do |r|
94
+ r.process { authorize(100, credit_card, options) }
95
+ r.process(:ignore_result) { void(r.authorization, options) }
96
+ end
97
+ end
10
98
 
11
99
  private
100
+
101
+ def commit(action, money, parameters)
102
+ parameters[:amount] = amount(money) unless action == 'VOID'
103
+
104
+ url = test? ? self.test_url : self.live_url
105
+ data = ssl_post(url, post_data(action, parameters))
106
+
107
+ response = parse(data)
108
+ response[:action] = action
109
+
110
+ message = message_from(response)
111
+
112
+ Response.new(success?(response), message, response,
113
+ :test => test?,
114
+ :authorization => response[:transaction_id],
115
+ :fraud_review => fraud_review?(response),
116
+ :avs_result => { :code => response[:avs_result_code] },
117
+ :cvv_result => response[:card_code]
118
+ )
119
+ end
120
+
121
+ def success?(response)
122
+ response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
123
+ end
124
+
125
+ def fraud_review?(response)
126
+ response[:response_code] == FRAUD_REVIEW
127
+ end
128
+
129
+ def parse(body)
130
+ fields = split(body)
131
+
132
+ results = {
133
+ :response_code => fields[RESPONSE_CODE].to_i,
134
+ :response_reason_code => fields[RESPONSE_REASON_CODE],
135
+ :response_reason_text => fields[RESPONSE_REASON_TEXT],
136
+ :avs_result_code => fields[AVS_RESULT_CODE],
137
+ :transaction_id => fields[TRANSACTION_ID],
138
+ :card_code => fields[CARD_CODE_RESPONSE_CODE],
139
+ :authorization_code => fields[AUTHORIZATION_CODE],
140
+ :cardholder_authentication_code => fields[CARDHOLDER_AUTH_CODE]
141
+ }
142
+ results
143
+ end
144
+
145
+ def post_data(action, parameters = {})
146
+ post = {}
147
+
148
+ post[:version] = API_VERSION
149
+ post[:login] = @options[:login]
150
+ post[:tran_key] = @options[:password]
151
+ post[:relay_response] = "FALSE"
152
+ post[:type] = action
153
+ post[:delim_data] = "TRUE"
154
+ post[:delim_char] = ","
155
+ post[:encap_char] = "$"
156
+ post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
157
+
158
+ request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
159
+ request
160
+ end
161
+
162
+ def add_currency_code(post, money, options)
163
+ post[:currency_code] = options[:currency] || currency(money)
164
+ end
165
+
166
+ def add_invoice(post, options)
167
+ post[:invoice_num] = options[:order_id]
168
+ post[:description] = options[:description]
169
+ end
170
+
12
171
  def add_creditcard(post, creditcard, options={})
13
- super
172
+ post[:card_num] = creditcard.number
173
+ post[:card_code] = creditcard.verification_value if creditcard.verification_value?
174
+ post[:exp_date] = expdate(creditcard)
175
+ post[:first_name] = creditcard.first_name
176
+ post[:last_name] = creditcard.last_name
177
+
14
178
  post[:recurring_billing] = "TRUE" if options[:recurring]
15
179
  end
16
- end
17
180
 
181
+ def add_payment_source(params, source, options={})
182
+ add_creditcard(params, source, options)
183
+ end
184
+
185
+ def add_customer_data(post, options)
186
+ if options.has_key? :email
187
+ post[:email] = options[:email]
188
+ post[:email_customer] = false
189
+ end
190
+
191
+ if options.has_key? :customer
192
+ post[:cust_id] = options[:customer] if Float(options[:customer]) rescue nil
193
+ end
194
+
195
+ if options.has_key? :ip
196
+ post[:customer_ip] = options[:ip]
197
+ end
198
+
199
+ if options.has_key? :cardholder_authentication_value
200
+ post[:cardholder_authentication_value] = options[:cardholder_authentication_value]
201
+ end
202
+
203
+ if options.has_key? :authentication_indicator
204
+ post[:authentication_indicator] = options[:authentication_indicator]
205
+ end
206
+
207
+ end
208
+
209
+ def add_duplicate_window(post)
210
+ unless duplicate_window.nil?
211
+ post[:duplicate_window] = duplicate_window
212
+ end
213
+ end
214
+
215
+ def add_address(post, options)
216
+ if address = options[:billing_address] || options[:address]
217
+ post[:address] = address[:address1].to_s
218
+ post[:company] = address[:company].to_s
219
+ post[:phone] = address[:phone].to_s
220
+ post[:zip] = address[:zip].to_s
221
+ post[:city] = address[:city].to_s
222
+ post[:country] = address[:country].to_s
223
+ post[:state] = address[:state].blank? ? 'n/a' : address[:state]
224
+ end
225
+
226
+ if address = options[:shipping_address]
227
+ post[:ship_to_first_name] = address[:first_name].to_s
228
+ post[:ship_to_last_name] = address[:last_name].to_s
229
+ post[:ship_to_address] = address[:address1].to_s
230
+ post[:ship_to_company] = address[:company].to_s
231
+ post[:ship_to_phone] = address[:phone].to_s
232
+ post[:ship_to_zip] = address[:zip].to_s
233
+ post[:ship_to_city] = address[:city].to_s
234
+ post[:ship_to_country] = address[:country].to_s
235
+ post[:ship_to_state] = address[:state].blank? ? 'n/a' : address[:state]
236
+ end
237
+ end
238
+
239
+ def message_from(results)
240
+ if results[:response_code] == DECLINED
241
+ return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
242
+ if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
243
+ return AVSResult.messages[ results[:avs_result_code] ]
244
+ end
245
+ end
246
+
247
+ (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
248
+ end
249
+
250
+ def split(response)
251
+ response[1..-2].split(/\$,\$/)
252
+ end
253
+ end
18
254
  end
19
255
  end
20
256