activemerchant 1.32.0 → 1.33.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 (52) hide show
  1. data/CHANGELOG +50 -0
  2. data/CONTRIBUTORS +8 -0
  3. data/README.md +6 -4
  4. data/lib/active_merchant/billing/check.rb +4 -3
  5. data/lib/active_merchant/billing/credit_card.rb +7 -3
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +27 -7
  7. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
  8. data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -185
  9. data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
  11. data/lib/active_merchant/billing/gateways/cc5.rb +0 -4
  12. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +94 -12
  13. data/lib/active_merchant/billing/gateways/garanti.rb +0 -4
  14. data/lib/active_merchant/billing/gateways/litle.rb +41 -11
  15. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +27 -6
  16. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -2
  17. data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
  18. data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
  19. data/lib/active_merchant/billing/gateways/orbital.rb +181 -48
  20. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
  21. data/lib/active_merchant/billing/gateways/paymill.rb +27 -13
  22. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +11 -6
  23. data/lib/active_merchant/billing/gateways/paypal_express.rb +25 -7
  24. data/lib/active_merchant/billing/gateways/pin.rb +5 -5
  25. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
  26. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
  28. data/lib/active_merchant/billing/gateways/sage.rb +10 -5
  29. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -0
  30. data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
  31. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -4
  32. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
  33. data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
  34. data/lib/active_merchant/billing/integrations/dwolla/common.rb +21 -0
  35. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +15 -6
  36. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +11 -6
  37. data/lib/active_merchant/billing/integrations/dwolla/return.rb +12 -4
  38. data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
  39. data/lib/active_merchant/billing/integrations/notification.rb +13 -8
  40. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +13 -1
  41. data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
  42. data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
  43. data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
  44. data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
  45. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +68 -5
  46. data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
  47. data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
  48. data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
  49. data/lib/active_merchant/version.rb +1 -1
  50. data.tar.gz.sig +0 -0
  51. metadata +72 -62
  52. metadata.gz.sig +0 -0
@@ -3,21 +3,47 @@ require 'digest/md5'
3
3
  module ActiveMerchant #:nodoc:
4
4
  module Billing #:nodoc:
5
5
  class BluePayGateway < Gateway
6
- class_attribute :live_url, :rebilling_url, :ignore_http_status
6
+ class_attribute :rebilling_url, :ignore_http_status
7
7
 
8
8
  self.live_url = 'https://secure.bluepay.com/interfaces/bp20post'
9
9
  self.rebilling_url = 'https://secure.bluepay.com/interfaces/bp20rebadmin'
10
10
 
11
11
  self.ignore_http_status = true
12
12
 
13
- RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT = 0, 2, 3
14
- AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE = 5, 6, 38
15
-
16
13
  CARD_CODE_ERRORS = %w( N S )
17
14
  AVS_ERRORS = %w( A E N R W Z )
18
15
  AVS_REASON_CODES = %w(27 45)
19
16
 
20
- class_attribute :duplicate_window
17
+ FRAUD_REVIEW_STATUSES = %w( E 0 )
18
+
19
+ FIELD_MAP = {
20
+ 'TRANS_ID' => :transaction_id,
21
+ 'STATUS' => :response_code,
22
+ 'AVS' => :avs_result_code,
23
+ 'CVV2'=> :card_code,
24
+ 'AUTH_CODE' => :authorization,
25
+ 'MESSAGE' => :message,
26
+ 'REBID' => :rebid,
27
+ 'TRANS_TYPE' => :trans_type,
28
+ 'PAYMENT_ACCOUNT_MASK' => :acct_mask,
29
+ 'CARD_TYPE' => :card_type,
30
+ }
31
+
32
+ REBILL_FIELD_MAP = {
33
+ 'REBILL_ID' => :rebill_id,
34
+ 'ACCOUNT_ID'=> :account_id,
35
+ 'USER_ID' => :user_id,
36
+ 'TEMPLATE_ID' => :template_id,
37
+ 'STATUS' => :status,
38
+ 'CREATION_DATE' => :creation_date,
39
+ 'NEXT_DATE' => :next_date,
40
+ 'LAST_DATE' => :last_date,
41
+ 'SCHED_EXPR' => :schedule,
42
+ 'CYCLES_REMAIN' => :cycles_remain,
43
+ 'REB_AMOUNT' => :rebill_amount,
44
+ 'NEXT_AMOUNT' => :next_amount,
45
+ 'USUAL_DATE' => :undoc_usual_date, # Not found in the bp20rebadmin API doc.
46
+ }
21
47
 
22
48
  self.supported_countries = ['US']
23
49
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
@@ -25,7 +51,6 @@ module ActiveMerchant #:nodoc:
25
51
  self.display_name = 'BluePay'
26
52
  self.money_format = :dollars
27
53
 
28
-
29
54
  # Creates a new BluepayGateway
30
55
  #
31
56
  # The gateway requires that a valid Account ID and Secret Key be passed
@@ -54,24 +79,12 @@ module ActiveMerchant #:nodoc:
54
79
  # * <tt>options</tt> -- A hash of optional parameters.
55
80
  def authorize(money, payment_object, options = {})
56
81
  post = {}
57
- post[:MASTER_ID] = ''
58
- if payment_object != nil && payment_object.class() != String
59
- payment_object.class() == ActiveMerchant::Billing::Check ?
60
- add_check(post, payment_object) :
61
- add_creditcard(post, payment_object)
62
- else
63
- post[:MASTER_ID] = payment_object
64
- end
82
+ add_payment_method(post, payment_object)
65
83
  add_invoice(post, options)
66
84
  add_address(post, options)
67
85
  add_customer_data(post, options)
68
- if options[:rebill] != nil
69
- post[:DO_REBILL] = '1'
70
- post[:REB_AMOUNT] = amount(options[:rebill_amount])
71
- post[:REB_FIRST_DATE] = options[:rebill_start_date]
72
- post[:REB_EXPR] = options[:rebill_expression]
73
- post[:REB_CYCLES] = options[:rebill_cycles]
74
- end
86
+ add_rebill(post, options) if options[:rebill]
87
+ add_duplicate_override(post, options)
75
88
  post[:TRANS_TYPE] = 'AUTH'
76
89
  commit('AUTH_ONLY', money, post)
77
90
  end
@@ -89,24 +102,12 @@ module ActiveMerchant #:nodoc:
89
102
  # * <tt>options</tt> -- A hash of optional parameters.,
90
103
  def purchase(money, payment_object, options = {})
91
104
  post = {}
92
- post[:MASTER_ID] = ''
93
- if payment_object != nil && payment_object.class() != String
94
- payment_object.class() == ActiveMerchant::Billing::Check ?
95
- add_check(post, payment_object) :
96
- add_creditcard(post, payment_object)
97
- else
98
- post[:MASTER_ID] = payment_object
99
- end
105
+ add_payment_method(post, payment_object)
100
106
  add_invoice(post, options)
101
107
  add_address(post, options)
102
108
  add_customer_data(post, options)
103
- if options[:rebill] != nil
104
- post[:DO_REBILL] = '1'
105
- post[:REB_AMOUNT] = amount(options[:rebill_amount])
106
- post[:REB_FIRST_DATE] = options[:rebill_start_date]
107
- post[:REB_EXPR] = options[:rebill_expression]
108
- post[:REB_CYCLES] = options[:rebill_cycles]
109
- end
109
+ add_rebill(post, options) if options[:rebill]
110
+ add_duplicate_override(post, options)
110
111
  post[:TRANS_TYPE] = 'SALE'
111
112
  commit('AUTH_CAPTURE', money, post)
112
113
  end
@@ -154,20 +155,17 @@ module ActiveMerchant #:nodoc:
154
155
  # If the payment_object is a token, then the transaction type will reverse a previous capture or purchase transaction, returning the funds to the customer. If the amount is nil, a full credit will be processed. This is referred to a REFUND transaction in BluePay.
155
156
  # If the payment_object is either a CreditCard or Check object, then the transaction type will be an unmatched credit placing funds in the specified account. This is referred to a CREDIT transaction in BluePay.
156
157
  # * <tt>options</tt> -- A hash of parameters.
157
- def refund(money, payment_object, options = {})
158
- post = {}
159
- post[:PAYMENT_ACCOUNT] = ''
160
- if payment_object != nil && payment_object.class() != String
161
- payment_object.class() == ActiveMerchant::Billing::Check ?
162
- add_check(post, payment_object) :
163
- add_creditcard(post, payment_object)
164
- post[:TRANS_TYPE] = 'CREDIT'
165
- else
166
- post[:MASTER_ID] = payment_object
167
- post[:TRANS_TYPE] = 'REFUND'
158
+ def refund(money, identification, options = {})
159
+ if(identification && !identification.kind_of?(String))
160
+ deprecated "refund should only be used to refund a referenced transaction"
161
+ return credit(money, identification, options)
168
162
  end
169
163
 
170
- options[:first_name] ? post[:NAME1] = options[:first_name] : post[:NAME1] = ''
164
+ post = {}
165
+ post[:PAYMENT_ACCOUNT] = ''
166
+ post[:MASTER_ID] = identification
167
+ post[:TRANS_TYPE] = 'REFUND'
168
+ post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
171
169
  post[:NAME2] = options[:last_name] if options[:last_name]
172
170
  post[:ZIP] = options[:zip] if options[:zip]
173
171
  add_invoice(post, options)
@@ -176,9 +174,24 @@ module ActiveMerchant #:nodoc:
176
174
  commit('CREDIT', money, post)
177
175
  end
178
176
 
179
- def credit(money, identification, options = {})
180
- deprecated CREDIT_DEPRECATION_MESSAGE
181
- refund(money, identification, options)
177
+ def credit(money, payment_object, options = {})
178
+ if(payment_object && payment_object.kind_of?(String))
179
+ deprecated "credit should only be used to credit a payment method"
180
+ return refund(money, payment_object, options)
181
+ end
182
+
183
+ post = {}
184
+ post[:PAYMENT_ACCOUNT] = ''
185
+ add_payment_method(post, payment_object)
186
+ post[:TRANS_TYPE] = 'CREDIT'
187
+
188
+ post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
189
+ post[:NAME2] = options[:last_name] if options[:last_name]
190
+ post[:ZIP] = options[:zip] if options[:zip]
191
+ add_invoice(post, options)
192
+ add_address(post, options)
193
+ add_customer_data(post, options)
194
+ commit('CREDIT', money, post)
182
195
  end
183
196
 
184
197
  # Create a new recurring payment.
@@ -214,9 +227,12 @@ module ActiveMerchant #:nodoc:
214
227
  # A money object of 1995 cents would be passed into the 'money' parameter.
215
228
  def recurring(money, payment_object, options = {})
216
229
  requires!(options, :rebill_start_date, :rebill_expression)
217
- options[:rebill] = '1'
218
- money == nil ? authorize(money, payment_object, options) :
219
- purchase(money, payment_object, options)
230
+ options[:rebill] = true
231
+ if money
232
+ purchase(money, payment_object, options)
233
+ else
234
+ authorize(money, payment_object, options)
235
+ end
220
236
  end
221
237
 
222
238
  # View a recurring payment
@@ -252,11 +268,11 @@ module ActiveMerchant #:nodoc:
252
268
  requires!(options, :rebill_id)
253
269
  post[:REBILL_ID] = options[:rebill_id]
254
270
  post[:TRANS_TYPE] = 'SET'
255
- post[:REB_AMOUNT] = amount(options[:rebill_amount]) if !options[:rebill_amount].nil?
256
- post[:NEXT_DATE] = options[:rebill_next_date] if !options[:rebill_next_date].nil?
257
- post[:REB_EXPR] = options[:rebill_expression] if !options[:rebill_expression].nil?
258
- post[:REB_CYCLES] = options[:rebill_cycles] if !options[:rebill_cycles].nil?
259
- post[:NEXT_AMOUNT] = options[:rebill_next_amount] if !options[:rebill_next_amount].nil?
271
+ post[:REB_AMOUNT] = amount(options[:rebill_amount]) if options[:rebill_amount]
272
+ post[:NEXT_DATE] = options[:rebill_next_date]
273
+ post[:REB_EXPR] = options[:rebill_expression]
274
+ post[:REB_CYCLES] = options[:rebill_cycles]
275
+ post[:NEXT_AMOUNT] = options[:rebill_next_amount]
260
276
  commit('rebill', 'nil', post)
261
277
  end
262
278
 
@@ -279,117 +295,133 @@ module ActiveMerchant #:nodoc:
279
295
  private
280
296
 
281
297
  def commit(action, money, fields)
282
- fields[:AMOUNT] = amount(money) unless (fields[:TRANS_TYPE] == 'VOID' or action == 'rebill')
283
- test? == true || @options[:test] == true ? fields[:MODE] = 'TEST' : fields[:MODE] = 'LIVE'
284
- action == 'rebill' ? begin url = rebilling_url; fields[:TAMPER_PROOF_SEAL] = calc_rebill_tps(fields) end : begin url = live_url; fields[:TAMPER_PROOF_SEAL] = calc_tps(amount(money), fields) end
298
+ fields[:AMOUNT] = amount(money) unless(fields[:TRANS_TYPE] == 'VOID' || action == 'rebill')
299
+ fields[:MODE] = (test? ? 'TEST' : 'LIVE')
285
300
  fields[:ACCOUNT_ID] = @options[:login]
286
- data = ssl_post url, post_data(action, fields)
287
- response = parse(data)
288
- message = message_from(response)
289
- test_mode = test? || fields[:MODE] == 'TEST'
290
- if (response.has_key?('TRANS_ID'))
291
- response_id = response['TRANS_ID'].to_s()
292
- elsif (response.has_key?('rebill_id'))
293
- response_id = response['rebill_id'][0]
301
+
302
+ if action == 'rebill'
303
+ url = rebilling_url
304
+ fields[:TAMPER_PROOF_SEAL] = calc_rebill_tps(fields)
294
305
  else
295
- response_id = response[TRANSACTION_ID]
306
+ url = live_url
307
+ fields[:TAMPER_PROOF_SEAL] = calc_tps(amount(money), fields)
296
308
  end
297
- avs = (response[AVS_RESULT_CODE] != '' ? response[AVS_RESULT_CODE] : '')
298
- cvv2 = (!response[CARD_CODE_RESPONSE_CODE].empty? ? response[CARD_CODE_RESPONSE_CODE] : '')
299
- Response.new(success?(response), message, response,
300
- :test => test_mode,
301
- :authorization => response_id,
302
- :fraud_review => fraud_review?(response),
303
- :avs_result => { :code => avs },
304
- :cvv_result => cvv2
305
- )
309
+ parse(ssl_post(url, post_data(action, fields)))
306
310
  end
307
311
 
308
- def success?(response)
309
- if (response['STATUS'] == '1' || message_from(response) =~ /approved/ || response.has_key?('rebill_id') || response[RESPONSE_REASON_TEXT] =~ /approved/)
310
- return true
311
- else
312
- return false
312
+ def parse_recurring(response_fields, opts={}) # expected status?
313
+ parsed = {}
314
+ response_fields.each do |k,v|
315
+ mapped_key = REBILL_FIELD_MAP.include?(k) ? REBILL_FIELD_MAP[k] : k
316
+ parsed[mapped_key] = v
313
317
  end
314
- end
315
318
 
316
- def fraud_review?(response)
317
- response['STATUS'] == 'E' || response['STATUS'] == '0' || response[RESPONSE_REASON_TEXT] =~ /being reviewed/
318
- end
319
+ success = parsed[:status] != 'error'
320
+ message = parsed[:status]
319
321
 
320
- def get_rebill_id(response)
321
- response['REBID'] if response_has.key?('REBID')
322
+ Response.new(success, message, parsed,
323
+ :test => test?,
324
+ :authorization => parsed[:rebill_id])
322
325
  end
323
326
 
324
327
  def parse(body)
325
- fields = CGI::parse(body)
326
- if fields.has_key?('MESSAGE') or fields.has_key?('rebill_id')
327
- if fields.has_key?('MESSAGE')
328
- fields['MESSAGE'][0] == "Missing ACCOUNT_ID" ? message = "The merchant login ID or password is invalid" : message = fields['MESSAGE']
329
- fields['MESSAGE'][0] =~ /Approved/ ? message = "This transaction has been approved" : message = fields['MESSAGE'] if message == fields['MESSAGE']
330
- fields['MESSAGE'][0] =~ /Expired/ ? message = "The credit card has expired" : message = fields['MESSAGE'] if message == fields['MESSAGE']
331
- fields.delete('MESSAGE')
332
- end
333
- fields.has_key?('STATUS') ? begin status = fields['STATUS']; fields.delete('STATUS') end : status = ''
334
- fields.has_key?('AVS') ? begin avs = fields['AVS']; fields.delete('AVS') end : avs = ''
335
- fields.has_key?('CVV2') ? begin cvv2 = fields['CVV2']; fields.delete('CVV2') end : cvv2 = ''
336
- fields.has_key?('MASTER_ID') ? begin trans_id = fields['MASTER_ID']; fields.delete('MASTER_ID') end : trans_id = ''
337
- fields[:avs_result_code] = avs
338
- fields[:card_code] = cvv2
339
- fields[:response_code] = status
340
- fields[:response_reason_code] = ''
341
- fields[:response_reason_text] = message
342
- fields[:transaction_id] = trans_id
343
- return fields
328
+ # The bp20api has max one value per form field.
329
+ response_fields = Hash[CGI::parse(body).map{|k,v| [k.upcase,v.first]}]
330
+
331
+ if response_fields.include? "REBILL_ID"
332
+ return parse_recurring(response_fields)
333
+ end
334
+
335
+ parsed = {}
336
+ response_fields.each do |k,v|
337
+ mapped_key = FIELD_MAP.include?(k) ? FIELD_MAP[k] : k
338
+ parsed[mapped_key] = v
344
339
  end
345
- # parse response if using other old API
346
- hash = Hash.new
347
- fields = fields.first[0].split(",")
348
- fields.each_index do |x|
349
- hash[x] = fields[x].tr('$','')
340
+
341
+ # normalize message
342
+ message = message_from(parsed)
343
+ success = parsed[:response_code] == '1'
344
+ Response.new(success, message, parsed,
345
+ :test => test?,
346
+ :authorization => (parsed[:rebid] && parsed[:rebid] != '' ? parsed[:rebid] : parsed[:transaction_id]),
347
+ :fraud_review => FRAUD_REVIEW_STATUSES.include?(parsed[:response_code]),
348
+ :avs_result => { :code => parsed[:avs_result_code] },
349
+ :cvv_result => parsed[:card_code]
350
+ )
351
+ end
352
+
353
+ def message_from(parsed)
354
+ message = parsed[:message]
355
+ if(parsed[:response_code].to_i == 2)
356
+ if CARD_CODE_ERRORS.include?(parsed[:card_code])
357
+ message = CVVResult.messages[parsed[:card_code]]
358
+ elsif AVS_ERRORS.include?(parsed[:avs_result_code])
359
+ message = AVSResult.messages[ parsed[:avs_result_code] ]
360
+ else
361
+ message = message.chomp('.')
362
+ end
363
+ elsif message == "Missing ACCOUNT_ID"
364
+ message = "The merchant login ID or password is invalid"
365
+ elsif message =~ /Approved/
366
+ message = "This transaction has been approved"
367
+ elsif message =~ /Expired/
368
+ message = "The credit card has expired"
350
369
  end
351
- hash
370
+ message
352
371
  end
353
372
 
354
373
  def add_invoice(post, options)
355
- post[:ORDER_ID] = options[:order_id] if options.has_key? :order_id
356
- post[:INVOICE_ID] = options[:invoice] if options.has_key? :invoice
357
- post[:invoice_num] = options[:order_id] if options.has_key? :order_id
358
- post[:MEMO] = options[:description] if options.has_key? :description
359
- post[:description] = options[:description] if options.has_key? :description
374
+ post[:ORDER_ID] = options[:order_id]
375
+ post[:INVOICE_ID] = options[:invoice]
376
+ post[:invoice_num] = options[:order_id]
377
+ post[:MEMO] = options[:description]
378
+ post[:description] = options[:description]
379
+ end
380
+
381
+ def add_payment_method(post, payment_object)
382
+ post[:MASTER_ID] = ''
383
+ case payment_object
384
+ when String
385
+ post[:MASTER_ID] = payment_object
386
+ when Check
387
+ add_check(post, payment_object)
388
+ else
389
+ add_creditcard(post, payment_object)
390
+ end
360
391
  end
361
392
 
362
393
  def add_creditcard(post, creditcard)
363
394
  post[:PAYMENT_TYPE] = 'CREDIT'
364
395
  post[:PAYMENT_ACCOUNT] = creditcard.number
365
- post[:CARD_CVV2] = creditcard.verification_value if
366
- creditcard.verification_value?
396
+ post[:CARD_CVV2] = creditcard.verification_value
367
397
  post[:CARD_EXPIRE] = expdate(creditcard)
368
398
  post[:NAME1] = creditcard.first_name
369
399
  post[:NAME2] = creditcard.last_name
370
400
  end
371
401
 
402
+ CHECK_ACCOUNT_TYPES = {
403
+ "checking" => "C",
404
+ "savings" => "S"
405
+ }
406
+
372
407
  def add_check(post, check)
373
408
  post[:PAYMENT_TYPE] = 'ACH'
374
- post[:PAYMENT_ACCOUNT] = check.account_type + ":" + check.routing_number + ":" + check.account_number
409
+ post[:PAYMENT_ACCOUNT] = [CHECK_ACCOUNT_TYPES[check.account_type], check.routing_number, check.account_number].join(":")
375
410
  post[:NAME1] = check.first_name
376
411
  post[:NAME2] = check.last_name
377
412
  end
378
413
 
379
414
  def add_customer_data(post, options)
380
- post[:EMAIL] = options[:email] if options.has_key? :email
381
- post[:CUSTOM_ID] = options[:customer] if options.has_key? :customer
415
+ post[:EMAIL] = options[:email]
416
+ post[:CUSTOM_ID] = options[:customer]
382
417
  end
383
418
 
384
- def add_duplicate_window(post)
385
- unless duplicate_window.nil?
386
- post[:duplicate_window] = duplicate_window
387
- post[:DUPLICATE_OVERRIDE] = duplicate_window
388
- end
419
+ def add_duplicate_override(post, options)
420
+ post[:DUPLICATE_OVERRIDE] = options[:duplicate_override]
389
421
  end
390
422
 
391
423
  def add_address(post, options)
392
- if address = options[:billing_address] || options[:address]
424
+ if address = (options[:shipping_address] || options[:billing_address] || options[:address])
393
425
  post[:NAME1] = address[:first_name]
394
426
  post[:NAME2] = address[:last_name]
395
427
  post[:ADDR1] = address[:address1]
@@ -397,27 +429,23 @@ module ActiveMerchant #:nodoc:
397
429
  post[:COMPANY_NAME] = address[:company]
398
430
  post[:PHONE] = address[:phone]
399
431
  post[:CITY] = address[:city]
400
- post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
432
+ post[:STATE] = (address[:state].blank? ? 'n/a' : address[:state])
401
433
  post[:ZIP] = address[:zip]
402
434
  post[:COUNTRY] = address[:country]
403
435
  end
404
- if address = options[:shipping_address]
405
- post[:NAME1] = address[:first_name]
406
- post[:NAME2] = address[:last_name]
407
- post[:ADDR1] = address[:address1]
408
- post[:ADDR1] = address[:address1]
409
- post[:COMPANY_NAME] = address[:company]
410
- post[:PHONE] = address[:phone]
411
- post[:ZIP] = address[:zip]
412
- post[:CITY] = address[:city]
413
- post[:COUNTRY] = address[:country]
414
- post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
415
- end
436
+ end
437
+
438
+ def add_rebill(post, options)
439
+ post[:DO_REBILL] = '1'
440
+ post[:REB_AMOUNT] = amount(options[:rebill_amount])
441
+ post[:REB_FIRST_DATE] = options[:rebill_start_date]
442
+ post[:REB_EXPR] = options[:rebill_expression]
443
+ post[:REB_CYCLES] = options[:rebill_cycles]
416
444
  end
417
445
 
418
446
  def post_data(action, parameters = {})
419
447
  post = {}
420
- post[:version] = '3.0'
448
+ post[:version] = '1'
421
449
  post[:login] = ''
422
450
  post[:tran_key] = ''
423
451
  post[:relay_response] = "FALSE"
@@ -427,60 +455,48 @@ module ActiveMerchant #:nodoc:
427
455
  post[:encap_char] = "$"
428
456
  post[:card_num] = '4111111111111111'
429
457
  post[:exp_date] = '1212'
430
- post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
431
- request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
432
- request
433
- end
434
-
435
- def message_from(results)
436
- if results[:response_code] == 2
437
- return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
438
- if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
439
- return AVSResult.messages[ results[:avs_result_code] ]
440
- end
441
- return (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
442
- end
443
- if results.has_key?(:response_reason_text)
444
- return results[:response_reason_text].to_s()
445
- end
446
- if !results.has_key?('STATUS')
447
- return results[RESPONSE_REASON_TEXT] ? results[RESPONSE_REASON_TEXT].chomp('.') : ''
448
- end
458
+ post[:solution_ID] = application_id if(application_id && application_id != "ActiveMerchant")
459
+ post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
449
460
  end
450
461
 
451
462
  def expdate(creditcard)
452
- year = sprintf("%.4i", creditcard.year)
453
- month = sprintf("%.2i", creditcard.month)
463
+ year = format(creditcard.year, :two_digits)
464
+ month = format(creditcard.month, :two_digits)
454
465
 
455
- "#{month}#{year[-2..-1]}"
466
+ "#{month}#{year}"
456
467
  end
457
468
 
458
469
  def calc_tps(amount, post)
459
- post[:NAME1] = '' if post[:NAME1].nil?
460
- digest = Digest::MD5.hexdigest(@options[:password] +
461
- @options[:login] + post[:TRANS_TYPE] +
462
- amount.to_s() + post[:MASTER_ID].to_s() +
463
- post[:NAME1].to_s() + post[:PAYMENT_ACCOUNT].to_s())
464
- return digest
470
+ post[:NAME1] ||= ''
471
+ Digest::MD5.hexdigest(
472
+ [
473
+ @options[:password],
474
+ @options[:login],
475
+ post[:TRANS_TYPE],
476
+ amount,
477
+ post[:MASTER_ID],
478
+ post[:NAME1],
479
+ post[:PAYMENT_ACCOUNT]
480
+ ].join("")
481
+ )
465
482
  end
466
483
 
467
484
  def calc_rebill_tps(post)
468
- digest = Digest::MD5.hexdigest(@options[:password] +
469
- @options[:login] + post[:TRANS_TYPE] + post[:REBILL_ID][0].to_s())
470
- return digest
485
+ Digest::MD5.hexdigest(
486
+ [
487
+ @options[:password],
488
+ @options[:login],
489
+ post[:TRANS_TYPE],
490
+ post[:REBILL_ID]
491
+ ].join("")
492
+ )
471
493
  end
472
494
 
473
495
  def handle_response(response)
474
- if ignore_http_status then
496
+ if ignore_http_status || (200...300).include?(response.code.to_i)
475
497
  return response.body
476
- else
477
- case response.code.to_i
478
- when 200...300
479
- response.body
480
- else
481
- raise ResponseError.new(response)
482
- end
483
498
  end
499
+ raise ResponseError.new(response)
484
500
  end
485
501
  end
486
502
  end
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
34
34
  money = amount(money)
35
35
  case normalize(credit_card_or_reference)
36
36
  when /1$/, AUTHORIZATION
37
- Response.new(true, SUCCESS_MESSAGE, {:paid_amount => money}, :test => true)
37
+ Response.new(true, SUCCESS_MESSAGE, {:paid_amount => money}, :test => true, :authorization => AUTHORIZATION)
38
38
  when /2$/
39
39
  Response.new(false, FAILURE_MESSAGE, {:paid_amount => money, :error => FAILURE_MESSAGE },:test => true)
40
40
  else