CnpOnline 9.14.0 → 11.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +7 -7
  2. data/CHANGELOG +23 -17
  3. data/CONTRIBUTORS +0 -0
  4. data/DESCRIPTION +1 -1
  5. data/LICENSE +1 -1
  6. data/README.md +5 -3
  7. data/Rakefile +5 -5
  8. data/Rakefile~ +5 -5
  9. data/SETUP.md +3 -3
  10. data/bin/Setup.rb +59 -41
  11. data/lib/Communications.rb +3 -3
  12. data/lib/Configuration.rb +52 -45
  13. data/lib/EnvironmentVariables.rb +5 -1
  14. data/lib/LitleBatchRequest.rb +72 -7
  15. data/lib/LitleListeners.rb +17 -1
  16. data/lib/LitleOnline.rb +3 -4
  17. data/lib/LitleOnlineRequest.rb +37 -7
  18. data/lib/LitleRequest.rb +315 -186
  19. data/lib/LitleTransaction.rb +212 -85
  20. data/lib/LitleXmlMapper.rb +4 -2
  21. data/lib/XMLFields.rb +384 -171
  22. data/lib/cacert.pem +0 -0
  23. data/samples/Auth/LitleAuthReversalTransaction.rb +2 -2
  24. data/samples/Auth/LitleAuthorizationTransaction.rb +1 -0
  25. data/samples/Auth/LitlePaymentFullLifeCycle.rb +12 -6
  26. data/samples/Batch/AccountUpdate.rb +1 -0
  27. data/samples/Batch/SampleBatchDriver.rb +2 -1
  28. data/samples/Capture/LitleCaptureGivenAuthTransaction.rb +2 -1
  29. data/samples/Capture/LitleCaptureTransaction.rb +2 -2
  30. data/samples/Capture/LitleForceCaptureTransaction.rb +2 -1
  31. data/samples/Capture/LitlePartialCapture.rb +3 -3
  32. data/samples/Credit/LitleCreditTransaction.rb +2 -2
  33. data/samples/Credit/LitleRefundTransaction.rb +2 -1
  34. data/samples/Other/LitleAvsTransaction.rb +2 -1
  35. data/samples/Other/LitleVoidTransaction.rb +2 -1
  36. data/samples/Paypage/FullPaypageLifeCycle.rb +7 -2
  37. data/samples/Run_all.rb +0 -0
  38. data/samples/Sale/LitleSaleTransaction.rb +2 -1
  39. data/samples/Sale/SampleSaleTransaction.rb +2 -1
  40. data/test/certification/certTest1_base.rb +52 -53
  41. data/test/certification/certTest2_authenhanced.rb +24 -25
  42. data/test/certification/certTest3_authreversal.rb +23 -26
  43. data/test/certification/certTest4_echeck.rb +18 -32
  44. data/test/certification/certTest5_token.rb +105 -106
  45. data/test/certification/certTest_batchAll.rb +47 -15
  46. data/test/functional/test_activate.rb +32 -4
  47. data/test/functional/test_activateReversal.rb +18 -5
  48. data/test/functional/test_auth.rb +94 -48
  49. data/test/functional/test_authReversal.rb +4 -1
  50. data/test/functional/test_balanceInquiry.rb +28 -3
  51. data/test/functional/test_batchStream.rb +2 -4
  52. data/test/functional/test_cancelSubscription.rb +2 -2
  53. data/test/functional/test_capture.rb +21 -14
  54. data/test/functional/test_captureGivenAuth.rb +15 -6
  55. data/test/functional/test_createPlan.rb +1 -1
  56. data/test/functional/test_credit.rb +14 -5
  57. data/test/functional/test_deactivate.rb +26 -3
  58. data/test/functional/test_deactivateReversal.rb +18 -5
  59. data/test/functional/test_depositReversal.rb +31 -19
  60. data/test/functional/test_echeckCredit.rb +34 -6
  61. data/test/functional/test_echeckRedeposit.rb +29 -2
  62. data/test/functional/test_echeckSale.rb +68 -11
  63. data/test/functional/test_echeckVerification.rb +32 -7
  64. data/test/functional/test_echeckVoid.rb +2 -1
  65. data/test/functional/test_forceCapture.rb +20 -6
  66. data/test/functional/test_fraudCheck.rb +3 -5
  67. data/test/functional/test_giftCardAuthReversal.rb +72 -0
  68. data/test/functional/test_giftCardCapture.rb +72 -0
  69. data/test/functional/test_giftCardCredit.rb +69 -0
  70. data/test/functional/test_litle_requests.rb +3 -6
  71. data/test/functional/test_load.rb +27 -3
  72. data/test/functional/test_loadReversal.rb +18 -5
  73. data/test/functional/test_override.rb +7 -3
  74. data/test/functional/test_pgp_litle_requests.rb +294 -0
  75. data/test/functional/test_queryTransaction.rb +152 -0
  76. data/test/functional/test_refundReversal.rb +18 -5
  77. data/test/functional/test_sale.rb +122 -159
  78. data/test/functional/test_token.rb +17 -11
  79. data/test/functional/test_unload.rb +27 -3
  80. data/test/functional/test_unloadReversal.rb +18 -5
  81. data/test/functional/test_updateCardValidationNumOnToken.rb +1 -0
  82. data/test/functional/test_updatePlan.rb +2 -1
  83. data/test/functional/test_updateSubscription.rb +3 -1
  84. data/test/functional/test_wallet.rb +74 -0
  85. data/test/functional/test_xmlfields.rb +22 -3
  86. data/test/functional/ts_all.rb +2 -0
  87. data/test/unit/test_LitleBatchRequest.rb +53 -5
  88. data/test/unit/test_LitleOnlineRequest.rb +5 -30
  89. data/test/unit/test_LitleRequest.rb +7 -6
  90. data/test/unit/test_LitleTransaction.rb +34 -5
  91. data/test/unit/test_LitleXmlMapper.rb +3 -0
  92. data/test/unit/test_activate.rb +22 -2
  93. data/test/unit/test_activateReversal.rb +15 -3
  94. data/test/unit/test_auth.rb +11 -9
  95. data/test/unit/test_balanceInquiry.rb +2 -2
  96. data/test/unit/test_capture.rb +2 -2
  97. data/test/unit/test_captureGivenAuth.rb +21 -1
  98. data/test/unit/test_credit.rb +1 -1
  99. data/test/unit/test_deactivate.rb +19 -0
  100. data/test/unit/test_deactivateReversal.rb +15 -3
  101. data/test/unit/test_depositReversal.rb +17 -5
  102. data/test/unit/test_echeckCredit.rb +19 -0
  103. data/test/unit/test_echeckRedeposit.rb +15 -0
  104. data/test/unit/test_echeckSale.rb +20 -1
  105. data/test/unit/test_echeckVerification.rb +6 -3
  106. data/test/unit/test_forceCapture.rb +1 -1
  107. data/test/unit/test_giftCardAuthReversal.rb +58 -0
  108. data/test/{functional/test_utf8.rb → unit/test_giftCardCapture.rb} +25 -12
  109. data/test/unit/test_giftCardCredit.rb +57 -0
  110. data/test/unit/test_load.rb +2 -2
  111. data/test/unit/test_loadReversal.rb +15 -3
  112. data/test/unit/test_pgp_LitleRequest +139 -0
  113. data/test/unit/test_queryTransaction.rb +105 -0
  114. data/test/unit/test_refundReversal.rb +15 -3
  115. data/test/unit/test_sale.rb +23 -3
  116. data/test/unit/test_token.rb +24 -20
  117. data/test/unit/test_unload.rb +2 -2
  118. data/test/unit/test_unloadReversal.rb +15 -3
  119. data/test/unit/test_wallet.rb +262 -0
  120. data/test/unit/ts_unit.rb +2 -1
  121. metadata +81 -100
@@ -16,6 +16,10 @@ module LitleOnline
16
16
  @fast_port = ''
17
17
  @printxml = false
18
18
  @timeout = 65
19
+ @useEncryption = false
20
+ @vantivPublicKeyID = ''
21
+ @passphrase = ''
22
+ @deleteBatchFies = false
19
23
  end
20
24
  end
21
- end
25
+ end
@@ -1,6 +1,5 @@
1
1
  =begin
2
2
  Copyright (c) 2017 Vantiv eCommerce
3
-
4
3
  Permission is hereby granted, free of charge, to any person
5
4
  obtaining a copy of this software and associated documentation
6
5
  files (the "Software"), to deal in the Software without
@@ -9,10 +8,8 @@ copy, modify, merge, publish, distribute, sublicense, and/or sell
9
8
  copies of the Software, and to permit persons to whom the
10
9
  Software is furnished to do so, subject to the following
11
10
  conditions:
12
-
13
11
  The above copyright notice and this permission notice shall be
14
12
  included in all copies or substantial portions of the Software.
15
-
16
13
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
14
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
15
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -25,9 +22,9 @@ OTHER DEALINGS IN THE SOFTWARE.
25
22
  require_relative 'Configuration'
26
23
 
27
24
  #
28
- # This class creates a new batch to which Vantiv eCommerce XML transactions are added.
25
+ # This class creates a new batch to which Litle XML transactions are added.
29
26
  # The batch is stored in the local file system until it is ready to be sent
30
- # to Vantiv eCommerce.
27
+ # to Litle.
31
28
  #
32
29
  module LitleOnline
33
30
  class LitleBatchRequest
@@ -45,7 +42,15 @@ module LitleOnline
45
42
  :captureGivenAuth=>{ :numCaptureGivenAuths=>0, :captureGivenAuthAmount=>0 },
46
43
  :forceCapture=>{ :numForceCaptures=>0, :forceCaptureAmount=>0 },
47
44
  :authReversal=>{ :numAuthReversals=>0, :authReversalAmount=>0 },
45
+ :fastAccessFunding=>{ :numFastAccessFunding=>0, :fastAccessFundingAmount=>0 },
46
+ #11.0 begin
47
+ :giftCardAuthReversal=>{ :numGiftCardAuthReversals=>0, :giftCardAuthReversalOriginalAmount=>0 },
48
+ #end
48
49
  :capture=>{ :numCaptures=>0, :captureAmount=>0 },
50
+ #11.0 begin
51
+ :giftCardCapture=>{ :numGiftCardCaptures=>0, :giftCardCaptureAmount=>0 },
52
+ :giftCardCredit=>{ :numGiftCardCredits=>0, :giftCardCreditAmount=>0 },
53
+ #end
49
54
  :echeckVerification=>{ :numEcheckVerification=>0, :echeckVerificationAmount=>0 },
50
55
  :echeckCredit=>{ :numEcheckCredit=>0, :echeckCreditAmount=>0 },
51
56
  :numEcheckRedeposit=>0,
@@ -74,7 +79,9 @@ module LitleOnline
74
79
  :load=>{:numLoads=>0, :loadAmount=>0},
75
80
  :unload=>{:numUnloads=>0, :unloadAmount=>0},
76
81
  :numBalanceInquirys=>0,
77
- :merchantSdk=>nil
82
+ :merchantSdk=>nil,
83
+ #SDK XML 10
84
+ :numFundingInstructionVoid=>0
78
85
  }
79
86
  @litle_txn = LitleTransaction.new
80
87
  @path_to_batch = nil
@@ -204,6 +211,27 @@ module LitleOnline
204
211
  add_txn_to_batch(transaction, :authReversal, options)
205
212
  end
206
213
 
214
+ def gift_card_auth_reversal(options)
215
+ transaction = @litle_txn.gift_card_auth_reversal(options)
216
+ @txn_counts[:giftCardAuthReversal][:numGiftCardAuthReversals] += 1
217
+ @txn_counts[:giftCardAuthReversal][:giftCardAuthReversalOriginalAmount] += options['amount'].to_i
218
+ add_txn_to_batch(transaction, :giftCardAuthReversal, options)
219
+ end
220
+
221
+ def gift_card_capture(options)
222
+ transaction = @litle_txn.gift_card_capture(options)
223
+ @txn_counts[:giftCardCapture][:numGiftCardCaptures] += 1
224
+ @txn_counts[:giftCardCapture][:giftCardCaptureAmount] += options['amount'].to_i
225
+ add_txn_to_batch(transaction, :giftCardCapture, options)
226
+ end
227
+
228
+ def gift_card_credit(options)
229
+ transaction = @litle_txn.gift_card_credit(options)
230
+ @txn_counts[:giftCardCredit][:numGiftCardCredits] += 1
231
+ @txn_counts[:giftCardCredit][:giftCardCreditAmount] += options['amount'].to_i
232
+ add_txn_to_batch(transaction, :giftCardCredit, options)
233
+ end
234
+
207
235
  def cancel_subscription(options)
208
236
  transaction = @litle_txn.cancel_subscription(options)
209
237
  @txn_counts[:numCancelSubscriptions] += 1
@@ -381,6 +409,19 @@ module LitleOnline
381
409
 
382
410
  add_txn_to_batch(transaction, :physicalCheckCredit, options)
383
411
  end
412
+
413
+
414
+ # Adding the numfundingInstructionVoid to the batch request
415
+ # Date: 01-25-2016
416
+ # Change Type: New
417
+ # Desc: Change proposed as a part of SDK XML 10 to incorporate the feature of voiding transactions
418
+ # on request.
419
+ def funding_txn_void(options)
420
+ transaction = @litle_txn.funding_txn_void(options)
421
+ @txn_counts[:numFundingInstructionVoid] += 1
422
+
423
+ add_txn_to_batch(transaction, :fundingInstructionVoid, options)
424
+ end
384
425
 
385
426
  def payFac_debit(options)
386
427
  transaction = @litle_txn.payFac_debit(options)
@@ -430,6 +471,14 @@ module LitleOnline
430
471
  add_txn_to_batch(transaction, :echeckSale, options)
431
472
  end
432
473
 
474
+ def fast_access_funding(options)
475
+ transaction = @litle_txn.fast_access_funding(options)
476
+ @txn_counts[:fastAccessFunding][:numFastAccessFunding] += 1
477
+ @txn_counts[:fastAccessFunding][:fastAccessFundingAmount] += options['amount'].to_i
478
+
479
+ add_txn_to_batch(transaction, :fastAccessFunding, options)
480
+ end
481
+
433
482
  def account_update(options)
434
483
 
435
484
  if(@au_batch == nil) then
@@ -485,8 +534,22 @@ module LitleOnline
485
534
  request.forceCaptureAmount = @txn_counts[:forceCapture][:forceCaptureAmount]
486
535
  request.numAuthReversals = @txn_counts[:authReversal][:numAuthReversals]
487
536
  request.authReversalAmount = @txn_counts[:authReversal][:authReversalAmount]
537
+ #11.4 begin
538
+ # request.numFastAccessFunding = @txn_counts[:fastAccessFunding][:numFastAccessFunding]
539
+ # request.fastAccessFundingAmount = @txn_counts[:fastAccessFunding][:fastAccessFundingAmount]
540
+ # 11.4 end
541
+ # 11.0 begin
542
+ request.numGiftCardAuthReversals = @txn_counts[:giftCardAuthReversal][:numGiftCardAuthReversals]
543
+ request.giftCardAuthReversalOriginalAmount = @txn_counts[:giftCardAuthReversal][:giftCardAuthReversalOriginalAmount]
544
+ # 11.0 end
488
545
  request.numCaptures = @txn_counts[:capture][:numCaptures]
489
546
  request.captureAmount = @txn_counts[:capture][:captureAmount]
547
+ # 11.0 begin
548
+ request.numGiftCardCaptures = @txn_counts[:giftCardCapture][:numGiftCardCaptures]
549
+ request.giftCardCaptureAmount = @txn_counts[:giftCardCapture][:giftCardCaptureAmount]
550
+ request.numGiftCardCredits = @txn_counts[:giftCardCredit][:numGiftCardCredits]
551
+ request.giftCardCreditAmount = @txn_counts[:giftCardCredit][:giftCardCreditAmount]
552
+ # 11.0 end
490
553
  request.numEcheckSales = @txn_counts[:echeckSale][:numEcheckSales]
491
554
  request.echeckSalesAmount = @txn_counts[:echeckSale][:echeckSalesAmount]
492
555
  request.numEcheckRedeposit = @txn_counts[:numEcheckRedeposit]
@@ -503,7 +566,9 @@ module LitleOnline
503
566
  request.vendorCreditAmount = @txn_counts[:vendorCredit][:vendorCreditAmount]
504
567
  request.numPhysicalCheckCredit = @txn_counts[:physicalCheckCredit][:numPhysicalCheckCredit]
505
568
  request.physicalCheckCreditAmount = @txn_counts[:physicalCheckCredit][:physicalCheckCreditAmount]
506
-
569
+ #SDK XML 10
570
+ request.numFundingInstructionVoid = @txn_counts[:numFundingInstructionVoid]
571
+
507
572
  request.numPayFacDebit = @txn_counts[:payFacDebit][:numPayFacDebit]
508
573
  request.payFacDebitAmount = @txn_counts[:payFacDebit][:payFacDebitAmount]
509
574
  request.numSubmerchantDebit = @txn_counts[:submerchantDebit][:numSubmerchantDebit]
@@ -232,7 +232,23 @@ module LitleOnline
232
232
 
233
233
  class FraudCheckListener < DefaultLitleListener
234
234
  def apply(duck)
235
- if(duck["type"] == "advancedFraudResult") then
235
+ if(duck["type"] == "advancedFraudResults") then
236
+ @action.call(duck)
237
+ end
238
+ end
239
+ end
240
+
241
+ class FastAccessFundingListener < DefaultLitleListener
242
+ def apply(duck)
243
+ if(duck["type"] == "fastAccessFundingResponse") then
244
+ @action.call(duck)
245
+ end
246
+ end
247
+ end
248
+
249
+ class ServiceStatusResponse < DefaultLitleListener
250
+ def apply(duck)
251
+ if(duck["type"] == "serviceStatusResponse") then
236
252
  @action.call(duck)
237
253
  end
238
254
  end
@@ -54,10 +54,9 @@ require_relative 'LitleRequest'
54
54
  require_relative 'LitleListeners'
55
55
  require_relative 'Configuration'
56
56
 
57
- # allows attribute values to be in double quotes,
58
- # required by Vantiv eCommerce Server
59
- REXML::Attribute.class_eval(%q^
57
+ #allows attribute values to be in double quotes, required by Litle Server
58
+ REXML::Attribute.class_eval( %q^
60
59
  def to_string
61
60
  %Q[#@expanded_name="#{to_s().gsub(/"/, '&quot;')}"]
62
61
  end
63
- ^)
62
+ ^ )
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
25
25
  require_relative 'Configuration'
26
26
 
27
27
  #
28
- # This class handles sending the Vantiv eCommerce online request
28
+ # This class handles sending the Litle online request
29
29
  #
30
30
  module LitleOnline
31
31
 
@@ -107,6 +107,31 @@ module LitleOnline
107
107
 
108
108
  commit(transaction, :depositReversal, options)
109
109
  end
110
+
111
+ #XML 11.0
112
+ def giftCardAuth_reversal(options)
113
+ transaction = @litle_transaction.giftCardAuth_reversal(options)
114
+
115
+ commit(transaction, :giftCardAuthReversal, options)
116
+ end
117
+
118
+ def giftCardCapture(options)
119
+ transaction = @litle_transaction.giftCardCapture(options)
120
+
121
+ commit(transaction, :giftCardCapture, options)
122
+ end
123
+
124
+ def giftCardCredit(options)
125
+ transaction = @litle_transaction.giftCardCredit(options)
126
+
127
+ commit(transaction, :giftCardCredit, options)
128
+ end
129
+
130
+ # def fast_access_funding(options)
131
+ # transaction = @litle_transaction.fast_access_funding(options)
132
+ #
133
+ # commit(transaction, :fastAccessFunding, options)
134
+ # end
110
135
 
111
136
  def refund_reversal(options)
112
137
  transaction = @litle_transaction.refund_reversal(options)
@@ -135,7 +160,7 @@ module LitleOnline
135
160
 
136
161
  def authorization(options)
137
162
  transaction = @litle_transaction.authorization(options)
138
-
163
+
139
164
  commit(transaction, :authorization, options)
140
165
  end
141
166
 
@@ -229,6 +254,12 @@ module LitleOnline
229
254
  commit(transaction, :echeckVoid, options)
230
255
  end
231
256
 
257
+ def query_Transaction(options)
258
+ transaction = @litle_transaction.query_Transaction(options)
259
+
260
+ commit(transaction, :queryTransaction, options)
261
+ end
262
+
232
263
  def fraud_check_request(options)
233
264
  transaction = @litle_transaction.fraud_check_request(options)
234
265
 
@@ -258,11 +289,10 @@ module LitleOnline
258
289
 
259
290
  request.authentication = authentication
260
291
  request.merchantId = get_merchant_id(options)
261
- request.version = '9.14'
292
+ request.version = '11.4'
262
293
  request.loggedInUser = get_logged_in_user(options)
263
- request.xmlns = 'http://www.litle.com/schema'
294
+ request.xmlns = "http://www.litle.com/schema"
264
295
  request.merchantSdk = get_merchant_sdk(options)
265
-
266
296
  request
267
297
  end
268
298
 
@@ -289,7 +319,7 @@ module LitleOnline
289
319
  end
290
320
 
291
321
  def get_merchant_sdk(options)
292
- options['merchantSdk'] || 'Ruby;9.14.0'
322
+ options['merchantSdk'] || 'Ruby;11.4'
293
323
  end
294
324
 
295
325
  def get_report_group(options)
@@ -299,7 +329,7 @@ module LitleOnline
299
329
  def get_config(field, options)
300
330
  options[field.to_s] == nil ? @config_hash[field.to_s] : options[field.to_s]
301
331
  end
302
-
332
+
303
333
  def get_logged_in_user(options)
304
334
  options['loggedInUser'] || nil
305
335
  end
@@ -1,6 +1,5 @@
1
1
  =begin
2
2
  Copyright (c) 2017 Vantiv eCommerce
3
-
4
3
  Permission is hereby granted, free of charge, to any person
5
4
  obtaining a copy of this software and associated documentation
6
5
  files (the "Software"), to deal in the Software without
@@ -9,10 +8,8 @@ copy, modify, merge, publish, distribute, sublicense, and/or sell
9
8
  copies of the Software, and to permit persons to whom the
10
9
  Software is furnished to do so, subject to the following
11
10
  conditions:
12
-
13
11
  The above copyright notice and this permission notice shall be
14
12
  included in all copies or substantial portions of the Software.
15
-
16
13
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
14
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
15
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -27,17 +24,35 @@ require 'net/sftp'
27
24
  require 'libxml'
28
25
  require 'crack/xml'
29
26
  require 'socket'
27
+ require 'iostreams'
28
+ require 'open3'
30
29
 
31
30
  include Socket::Constants
32
31
  #
33
- # This class handles sending the Litle Request
34
- # (which is actually a series of batches!)
32
+ # This class handles sending the Litle Request (which is actually a series of batches!)
35
33
  #
36
34
 
35
+
36
+ SFTP_USERNAME_CONFIG_NAME = :sftp_username
37
+ SFTP_PASSWORD_CONFIG_NAME = :sftp_password
38
+ SFTP_URL_CONFIG_NAME = :sftp_url
39
+ SFTP_USE_ENCRYPTION_CONFIG_NAME = :useEncryption
40
+ SFTP_DELETE_BATCH_FILES_CONFIG_NAME = :deleteBatchFiles
41
+
42
+ REQUEST_PATH_DIR = 'requests/'
43
+ REQUEST_FILE_PREFIX = 'request_'
44
+ ENCRYPTED_PATH_DIR = 'encrypted/'
45
+ ENCRYPTED_FILE_SUFFIX = '.encrypted'
46
+ RESPONSE_PATH_DIR = 'responses/'
47
+ RESPONSE_FILE_PREFIX = 'response_'
48
+
49
+ SENT_FILE_SUFFIX = '.sent'
50
+ RECEIVED_FILE_SUFFIX = '.received'
51
+ COMPLETE_FILE_SUFFIX = '.complete'
52
+
37
53
  module LitleOnline
38
54
  class LitleRequest
39
- include XML::Mapping
40
-
55
+ #include XML::Mapping
41
56
  def initialize(options = {})
42
57
  #load configuration data
43
58
  @config_hash = Configuration.new.config
@@ -49,7 +64,7 @@ module LitleOnline
49
64
  @options = options
50
65
  # current time out set to 2 mins
51
66
  # this value is in seconds
52
- @RESPONSE_TIME_OUT = 360
67
+ @RESPONSE_TIME_OUT = 520
53
68
  @POLL_DELAY = 0
54
69
  @responses_expected = 0
55
70
  end
@@ -66,11 +81,11 @@ module LitleOnline
66
81
  ts += Time::now.usec.to_s
67
82
  end
68
83
 
69
- if (File.file?(path)) then
70
- raise 'Entered a file not a path.'
84
+ if(File.file?(path)) then
85
+ raise RuntimeError, "Entered a file not a path."
71
86
  end
72
87
 
73
- if (path[-1, 1] != '/' and path[-1, 1] != '\\') then
88
+ if(path[-1,1] != '/' and path[-1,1] != '\\') then
74
89
  path = path + File::SEPARATOR
75
90
  end
76
91
 
@@ -78,34 +93,33 @@ module LitleOnline
78
93
  Dir.mkdir(path)
79
94
  end
80
95
 
81
- @path_to_request = path + 'request_' + ts
96
+ @path_to_request = path + REQUEST_FILE_PREFIX + ts
82
97
  @path_to_batches = @path_to_request + '_batches'
83
98
 
84
99
  if File.file?(@path_to_request) or File.file?(@path_to_batches) then
85
100
  create_new_litle_request(path)
101
+
86
102
  return
87
103
  end
88
104
 
89
105
  File.open(@path_to_request, 'a+') do |file|
90
- file.write('')
106
+ file.write("")
91
107
  end
92
108
  File.open(@path_to_batches, 'a+') do |file|
93
- file.write('')
109
+ file.write("")
94
110
  end
95
111
  end
96
112
 
97
- # Adds a batch to the LitleRequest. If the batch is open when passed,
98
- # it will be closed prior to being added.
113
+ # Adds a batch to the LitleRequest. If the batch is open when passed, it will be closed prior to being added.
99
114
  # Params:
100
- # +arg+:: a +LitleBatchRequest+ containing the transactions you wish to
101
- # send or a +String+ specifying the
115
+ # +arg+:: a +LitleBatchRequest+ containing the transactions you wish to send or a +String+ specifying the
102
116
  # path to the batch file
103
117
  def commit_batch(arg)
104
- path_to_batch = ''
105
- # they passed a batch
118
+ path_to_batch = ""
119
+ #they passed a batch
106
120
  if arg.kind_of?(LitleBatchRequest) then
107
121
  path_to_batch = arg.get_batch_name
108
- if ((au = arg.get_au_batch) != nil) then
122
+ if((au = arg.get_au_batch) != nil) then
109
123
  # also commit the account updater batch
110
124
  commit_batch(au)
111
125
  end
@@ -114,20 +128,18 @@ module LitleOnline
114
128
  elsif arg.kind_of?(String) then
115
129
  path_to_batch = arg
116
130
  else
117
- raise 'You entered neither a path nor a batch. Game over :('
131
+ raise RuntimeError, "You entered neither a path nor a batch."
118
132
  end
119
- # the batch isn't closed. let's help a brother out
133
+ #the batch isn't closed. let's help a brother out
120
134
  if (ind = path_to_batch.index(/\.closed/)) == nil then
121
135
  if arg.kind_of?(String) then
122
136
  new_batch = LitleBatchRequest.new
123
137
  new_batch.open_existing_batch(path_to_batch)
124
138
  new_batch.close_batch()
125
139
  path_to_batch = new_batch.get_batch_name
126
- # if we passed a path to an AU batch, then new_batch will be a new,
127
- # empty batch and the batch we passed
128
- # will be in the AU batch variable. thus, we wanna grab that file name
129
- # and remove the empty batch.
130
- if (new_batch.get_au_batch != nil) then
140
+ # if we passed a path to an AU batch, then new_batch will be a new, empty batch and the batch we passed
141
+ # will be in the AU batch variable. thus, we wanna grab that file name and remove the empty batch.
142
+ if(new_batch.get_au_batch != nil) then
131
143
  File.remove(path_to_batch)
132
144
  path_to_batch = new_batch.get_au_batch.get_batch_name
133
145
  end
@@ -146,14 +158,13 @@ module LitleOnline
146
158
  if (@num_total_transactions + transactions_in_batch) > @MAX_NUM_TRANSACTIONS then
147
159
  finish_request
148
160
  initialize(@options)
149
- create_new_litle_request
150
- else # otherwise, let's add it line by line to the request doc
161
+ create_new_litle_request #(path_to_batch)
162
+ else #otherwise, let's add it line by line to the request doc
151
163
  # @num_batch_requests += 1
152
- # how long we want to wait around for the
153
- # FTP server to get us a response
164
+ #how long we wnat to wait around for the FTP server to get us a response
154
165
  @RESPONSE_TIME_OUT += 90 + (transactions_in_batch * 0.25)
155
- # don't start looking until there could possibly be a response
156
- @POLL_DELAY += 30 +(transactions_in_batch * 0.02)
166
+ #don't start looking until there could possibly be a response
167
+ @POLL_DELAY += 30 +(transactions_in_batch * 0.02)
157
168
  @num_total_transactions += transactions_in_batch
158
169
  # Don't add empty batches
159
170
  @num_batch_requests += 1 unless transactions_in_batch.eql?(0)
@@ -168,23 +179,23 @@ module LitleOnline
168
179
  end
169
180
 
170
181
  # Adds an RFRRequest to the LitleRequest.
171
- # params:
172
- # +options+:: a required +Hash+ containing configuration info for the RFRRequest. If the RFRRequest is for a batch, then the
182
+ # params:
183
+ # +options+:: a required +Hash+ containing configuration info for the RFRRequest. If the RFRRequest is for a batch, then the
173
184
  # litleSessionId is required as a key/val pair. If the RFRRequest is for account updater, then merchantId and postDay are required
174
185
  # as key/val pairs.
175
186
  # +path+:: optional path to save the new litle request containing the RFRRequest at
176
187
  def add_rfr_request(options, path = (File.dirname(@path_to_batches)))
177
188
 
178
189
  rfrrequest = LitleRFRRequest.new
179
- if (options['litleSessionId']) then
190
+ if(options['litleSessionId']) then
180
191
  rfrrequest.litleSessionId = options['litleSessionId']
181
- elsif (options['merchantId'] and options['postDay']) then
192
+ elsif(options['merchantId'] and options['postDay']) then
182
193
  accountUpdate = AccountUpdateFileRequestData.new
183
194
  accountUpdate.merchantId = options['merchantId']
184
195
  accountUpdate.postDay = options['postDay']
185
196
  rfrrequest.accountUpdateFileRequestData = accountUpdate
186
197
  else
187
- raise ArgumentError, "For an RFR Request, you must specify either a litleSessionId for an RFRRequest for batch or a merchantId
198
+ raise ArgumentError, "For an RFR Request, you must specify either a litleSessionId for an RFRRequest for batch or a merchantId
188
199
  and a postDay for an RFRRequest for account updater."
189
200
  end
190
201
 
@@ -196,10 +207,10 @@ module LitleOnline
196
207
  authentication.password = get_config(:password, options)
197
208
 
198
209
  litleRequest.authentication = authentication
199
- litleRequest.numBatchRequests = '0'
210
+ litleRequest.numBatchRequests = "0"
200
211
 
201
- litleRequest.version = '9.14'
202
- litleRequest.xmlns = 'http://www.litle.com/schema'
212
+ litleRequest.version = '11.4'
213
+ litleRequest.xmlns = "http://www.litle.com/schema"
203
214
 
204
215
 
205
216
  xml = litleRequest.save_to_xml.to_s
@@ -210,11 +221,11 @@ module LitleOnline
210
221
  rescue NoMethodError # ruby 1.8.7 fix
211
222
  ts += Time::now.usec.to_s
212
223
  end
213
- if File.file?(path) then
214
- raise 'Entered a file not a path.'
224
+ if(File.file?(path)) then
225
+ raise RuntimeError, "Entered a file not a path."
215
226
  end
216
227
 
217
- if (path[-1, 1] != '/' and path[-1, 1] != '\\') then
228
+ if(path[-1,1] != '/' and path[-1,1] != '\\') then
218
229
  path = path + File::SEPARATOR
219
230
  end
220
231
 
@@ -222,12 +233,12 @@ module LitleOnline
222
233
  Dir.mkdir(path)
223
234
  end
224
235
 
225
- path_to_request = path + 'request_' + ts
236
+ path_to_request = path + REQUEST_FILE_PREFIX + ts
226
237
 
227
238
  File.open(path_to_request, 'a+') do |file|
228
239
  file.write xml
229
240
  end
230
- File.rename(path_to_request, path_to_request + '.complete')
241
+ File.rename(path_to_request, path_to_request + COMPLETE_FILE_SUFFIX)
231
242
  @RESPONSE_TIME_OUT += 90
232
243
  end
233
244
 
@@ -236,51 +247,36 @@ module LitleOnline
236
247
  # +path+:: A +String+ containing the path to the folder on disc where LitleRequests are located.
237
248
  # This should be the same location where the LitleRequests were written to. If no path is explicitly
238
249
  # provided, then we use the directory where the current working batches file is stored.
239
- # +options+:: An (option) +Hash+ containing the username, password, and URL to attempt to sFTP to.
250
+ # +options+:: An (option) +Hash+ containing the username, password, useEncryption and URL to attempt to sFTP to.
240
251
  # If not provided, the values will be populated from the configuration file.
241
252
  def send_to_litle(path = (File.dirname(@path_to_batches)), options = {})
242
- username = get_config(:sftp_username, options)
243
- password = get_config(:sftp_password, options)
253
+ use_encryption = get_config(SFTP_USE_ENCRYPTION_CONFIG_NAME, options)
254
+ username = get_config(SFTP_USERNAME_CONFIG_NAME, options)
255
+ password = get_config(SFTP_PASSWORD_CONFIG_NAME, options)
256
+ delete_batch_files = get_config(SFTP_DELETE_BATCH_FILES_CONFIG_NAME, options)
257
+ url = get_config(SFTP_URL_CONFIG_NAME, options)
244
258
 
245
- url = get_config(:sftp_url, options)
246
-
247
- if username == nil or password == nil or url == nil then
248
- raise ArgumentError, 'You are not configured to use sFTP for batch processing. Please run /bin/Setup.rb again!'
259
+ if(username == nil or password == nil or url == nil) then
260
+ raise ArgumentError, "You are not configured to use sFTP for batch processing. Please run /bin/Setup.rb again!"
249
261
  end
262
+ path = path_to_requests = prepare_for_sftp(path, use_encryption)
250
263
 
251
- if (path[-1, 1] != '/' && path[-1, 1] != '\\') then
252
- path = path + File::SEPARATOR
264
+ if use_encryption
265
+ encrypted_path = path_to_requests + ENCRYPTED_PATH_DIR
266
+ encrypt_request_files(path, encrypted_path, options)
267
+ path_to_requests = encrypted_path
253
268
  end
254
269
 
255
- begin
256
- Net::SFTP.start(url, username, :password => password) do |sftp|
257
-
258
- # our folder is /SHORTNAME/SHORTNAME/INBOUND
259
- Dir.foreach(path) do |filename|
260
- # we have a complete report according to filename regex
261
- if (filename =~ /request_\d+.complete\z/) != nil then
262
- # adding .prg extension per the XML
263
- File.rename(path + filename, path + filename + '.prg')
264
- end
265
- end
266
-
267
- @responses_expected = 0
268
- Dir.foreach(path) do |filename|
269
- if (filename =~ /request_\d+.complete.prg\z/) != nil then
270
- # upload the file
271
- sftp.upload!(path + filename, '/inbound/' + filename)
272
- @responses_expected += 1
273
- # rename now that we're done
274
- sftp.rename!('/inbound/'+ filename, '/inbound/' + filename.gsub('prg', 'asc'))
275
- File.rename(path + filename, path + filename.gsub('prg', 'sent'))
276
- end
277
- end
270
+ @responses_expected = upload_to_sftp(path_to_requests, url, username, password, use_encryption)
271
+ if delete_batch_files
272
+ delete_files_in_path(path_to_requests, /#{REQUEST_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}#{ENCRYPTED_FILE_SUFFIX}?#{SENT_FILE_SUFFIX}\z/)
273
+ if use_encryption
274
+ delete_files_in_path(path, /#{REQUEST_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}#{SENT_FILE_SUFFIX}\z/)
278
275
  end
279
- rescue Net::SSH::AuthenticationFailed
280
- raise ArgumentError, 'The sFTP credentials provided were incorrect. Try again!'
281
276
  end
282
277
  end
283
278
 
279
+
284
280
  # Sends all previously unsent LitleRequests in the specified directory to the Litle server
285
281
  # by use of fast batch. All results will be written to disk as we get them. Note that use
286
282
  # of fastbatch is strongly discouraged!
@@ -288,40 +284,43 @@ module LitleOnline
288
284
  url = get_config(:fast_url, options)
289
285
  port = get_config(:fast_port, options)
290
286
 
291
- if url == nil or url == '' then
292
- raise ArgumentError, 'A URL for fastbatch was not specified in the config file or passed options. Reconfigure and try again.'
287
+
288
+ if(url == nil or url == "") then
289
+ raise ArgumentError, "A URL for fastbatch was not specified in the config file or passed options. Reconfigure and try again."
293
290
  end
294
291
 
295
- if (port == "" or port == nil) then
296
- raise ArgumentError, 'A port number for fastbatch was not specified in the config file or passed options. Reconfigure and try again.'
292
+ if(port == "" or port == nil) then
293
+ raise ArgumentError, "A port number for fastbatch was not specified in the config file or passed options. Reconfigure and try again."
297
294
  end
298
295
 
299
- if (path[-1, 1] != '/' && path[-1, 1] != '\\') then
296
+ if(path[-1,1] != '/' && path[-1,1] != '\\') then
300
297
  path = path + File::SEPARATOR
301
298
  end
302
299
 
303
- if (!File.directory?(path + 'responses/')) then
304
- Dir.mkdir(path + 'responses/')
300
+ if (!File.directory?(path + RESPONSE_PATH_DIR)) then
301
+ Dir.mkdir(path + RESPONSE_PATH_DIR)
305
302
  end
306
303
 
307
304
  Dir.foreach(path) do |filename|
308
- if ((filename =~ /request_\d+.complete\z/) != nil) then
305
+ if((filename =~ /#{REQUEST_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}\z/) != nil) then
309
306
  begin
310
- socket = TCPSocket.open(url, port.to_i)
307
+ socket = TCPSocket.open(url,port.to_i)
311
308
  ssl_context = OpenSSL::SSL::SSLContext.new()
312
309
  ssl_context.ssl_version = :SSLv23
313
310
  ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
314
311
  ssl_socket.sync_close = true
315
312
  ssl_socket.connect
313
+
316
314
  rescue => e
317
- raise 'A connection could not be established. Are you sure you have the correct credentials? Exception: ' + e.message
315
+ raise "A connection couldn't be established. Are you sure you have the correct credentials? Exception: " + e.message
318
316
  end
319
317
 
320
318
  File.foreach(path + filename) do |li|
321
319
  ssl_socket.puts li
320
+
322
321
  end
323
- File.rename(path + filename, path + filename + '.sent')
324
- File.open(path + 'responses/' + (filename + '.asc.received').gsub('request', 'response'), 'a+') do |fo|
322
+ File.rename(path + filename, path + filename + SENT_FILE_SUFFIX)
323
+ File.open(path + RESPONSE_PATH_DIR + (filename + '.asc' + RECEIVED_FILE_SUFFIX).gsub("request", "response"), 'a+') do |fo|
325
324
  while line = ssl_socket.gets
326
325
  fo.puts(line)
327
326
  end
@@ -331,7 +330,6 @@ module LitleOnline
331
330
  end
332
331
  end
333
332
 
334
-
335
333
  # Grabs response files over SFTP from Litle.
336
334
  # Params:
337
335
  # +args+:: An (optional) +Hash+ containing values for the number of responses expected, the
@@ -339,73 +337,25 @@ module LitleOnline
339
337
  # password with which to connect ot the sFTP server, and the URL to connect over sFTP. Values not
340
338
  # provided in the hash will be populate automatically based on our best guess
341
339
  def get_responses_from_server(args = {})
340
+ use_encryption = get_config(SFTP_USE_ENCRYPTION_CONFIG_NAME, args)
342
341
  @responses_expected = args[:responses_expected] ||= @responses_expected
343
- response_path = args[:response_path] ||= (File.dirname(@path_to_batches) + '/responses/')
344
- username = get_config(:sftp_username, args)
345
- password = get_config(:sftp_password, args)
346
- url = get_config(:sftp_url, args)
342
+ response_path = args[:response_path] ||= (File.dirname(@path_to_batches) + '/' + RESPONSE_PATH_DIR)
343
+ username = get_config(SFTP_USERNAME_CONFIG_NAME, args)
344
+ password = get_config(SFTP_PASSWORD_CONFIG_NAME, args)
345
+ url = get_config(SFTP_URL_CONFIG_NAME, args)
347
346
 
348
- if (username == nil or password == nil or url == nil) then
349
- raise ConfigurationException, 'You are not configured to use sFTP for batch processing. Please run /bin/Setup.rb again!'
347
+ if(username == nil or password == nil or url == nil) then
348
+ raise ArgumentError, "You are not configured to use sFTP for batch processing. Please run /bin/Setup.rb again!"
350
349
  end
351
-
352
- if (response_path[-1, 1] != '/' && response_path[-1, 1] != '\\') then
353
- response_path = response_path + File::SEPARATOR
350
+ response_path = prepare_for_sftp(response_path, use_encryption)
351
+ if use_encryption
352
+ response_path += ENCRYPTED_PATH_DIR
354
353
  end
355
354
 
356
- if (!File.directory?(response_path)) then
357
- Dir.mkdir(response_path)
358
- end
359
- begin
360
- responses_grabbed = 0
361
- Net::SFTP.start(url, username, :password => password) do |sftp|
362
- # clear out the sFTP outbound dir prior to checking for new files, avoids leaving files on the server
363
- # if files are left behind we are not counting then towards the expected total
364
- sftp.dir.foreach('/outbound/') do |entry|
365
- if ((entry.name =~ /request_\d+.complete.asc\z/) != nil) then
366
- sftp.download!('/outbound/' + entry.name, response_path + entry.name.gsub('request', 'response') + '.received')
367
- 3.times {
368
- begin
369
- sftp.remove!('/outbound/' + entry.name)
370
- break
371
- rescue Net::SFTP::StatusException
372
- # try, try, try again
373
- puts "We couldn't remove it! Try again"
374
- end
375
- }
376
- end
377
- end
378
- end
379
- # wait until a response has a possibility of being there
380
- sleep(@POLL_DELAY)
381
- time_begin = Time.now
382
- Net::SFTP.start(url, username, :password => password) do |sftp|
383
- while ((Time.now - time_begin) < @RESPONSE_TIME_OUT && responses_grabbed < @responses_expected)
384
- # sleep for 60 seconds, ¿no es bueno?
385
- sleep(60)
386
- sftp.dir.foreach('/outbound/') do |entry|
387
- if ((entry.name =~ /request_\d+.complete.asc\z/) != nil) then
388
- sftp.download!('/outbound/' + entry.name, response_path + entry.name.gsub('request', 'response') + '.received')
389
- responses_grabbed += 1
390
- 3.times {
391
- begin
392
- sftp.remove!('/outbound/' + entry.name)
393
- break
394
- rescue Net::SFTP::StatusException
395
- # try, try, try again
396
- puts "We couldn't remove it! Try again"
397
- end
398
- }
399
- end
400
- end
401
- end
402
- # if our timeout timed out, we're having problems
403
- if responses_grabbed < @responses_expected then
404
- raise 'We timed out in waiting for a response from the server. :('
405
- end
406
- end
407
- rescue Net::SSH::AuthenticationFailed
408
- raise ArgumentError, 'The sFTP credentials provided were incorrect. Try again!'
355
+ download_from_sftp(response_path, url, username, password)
356
+
357
+ if use_encryption
358
+ decrypt_response_files(response_path, args)
409
359
  end
410
360
  end
411
361
 
@@ -414,35 +364,44 @@ module LitleOnline
414
364
  # for a transaction listener (see +DefaultLitleListener+). It may also include a batch listener and a
415
365
  # custom path where response files from the server are located (if it is not provided, we'll guess the position)
416
366
  def process_responses(args)
417
- # the transaction listener is required
418
- if (!args.has_key?(:transaction_listener)) then
419
- raise ArgumentError, 'The arguments hash must contain an entry for transaction listener!'
367
+ #the transaction listener is required
368
+ if(!args.has_key?(:transaction_listener)) then
369
+ raise ArgumentError, "The arguments hash must contain an entry for transaction listener!"
420
370
  end
421
371
 
422
372
  transaction_listener = args[:transaction_listener]
423
373
  batch_listener = args[:batch_listener] ||= nil
424
- path_to_responses = args[:path_to_responses] ||= (File.dirname(@path_to_batches) + '/responses/')
374
+ path_to_responses = args[:path_to_responses] ||= (File.dirname(@path_to_batches) + '/' + RESPONSE_PATH_DIR)
375
+ delete_batch_files = args[:deleteBatchFiles] ||= get_config(:deleteBatchFiles, args)
376
+
377
+ if(path_to_responses[-1,1] != '/' && path_to_responses[-1,1] != '\\') then
378
+ path_to_responses = path_to_responses + File::SEPARATOR
379
+ end
425
380
 
426
381
  Dir.foreach(path_to_responses) do |filename|
427
- if (filename =~ /response_\d+.complete.asc.received\z/) != nil then
382
+ if ((filename =~ /#{RESPONSE_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}.asc#{RECEIVED_FILE_SUFFIX}\z/) != nil) then
428
383
  process_response(path_to_responses + filename, transaction_listener, batch_listener)
429
384
  File.rename(path_to_responses + filename, path_to_responses + filename + '.processed')
430
385
  end
431
386
  end
387
+
388
+ if delete_batch_files
389
+ delete_files_in_path(path_to_responses, /#{RESPONSE_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}.asc#{RECEIVED_FILE_SUFFIX}.processed\z/)
390
+ end
432
391
  end
433
392
 
434
393
  # Params:
435
394
  # +path_to_response+:: The path to a specific .asc file to process
436
- # +transaction_listener+:: A listener to be applied to the hash of each transaction
395
+ # +transaction_listener+:: A listener to be applied to the hash of each transaction
437
396
  # (see +DefaultLitleListener+)
438
- # +batch_listener+:: An (optional) listener to be applied to the hash of each batch.
439
- # Note that this will om-nom-nom quite a bit of memory
397
+ # +batch_listener+:: An (optional) listener to be applied to the hash of each batch.
398
+ # Note that this will om-nom-nom quite a bit of memory
440
399
  def process_response(path_to_response, transaction_listener, batch_listener = nil)
441
400
  reader = LibXML::XML::Reader.file(path_to_response)
442
401
  reader.read # read into the root node
443
- # if the response attribute is nil, we're dealing with an RFR and everything is a-okay
444
- if reader.get_attribute('response') != '0' and reader.get_attribute('response') != nil then
445
- raise 'Error parsing Litle Request: ' + reader.get_attribute('message')
402
+ #if the response attribute is nil, we're dealing with an RFR and everything is a-okay
403
+ if reader.get_attribute('response') != "0" and reader.get_attribute('response') != nil then
404
+ raise RuntimeError, "Error parsing Litle Request: " + reader.get_attribute("message")
446
405
  end
447
406
 
448
407
  reader.read
@@ -450,21 +409,21 @@ module LitleOnline
450
409
  while true and count < 500001 do
451
410
 
452
411
  count += 1
453
- if reader.node == nil then
412
+ if(reader.node == nil) then
454
413
  return false
455
414
  end
456
415
 
457
416
  case reader.node.name.to_s
458
- when 'batchResponse'
417
+ when "batchResponse"
459
418
  reader.read
460
- when 'litleResponse'
419
+ when "litleResponse"
461
420
  return false
462
- when 'text'
421
+ when "text"
463
422
  reader.read
464
423
  else
465
424
  xml = reader.read_outer_xml
466
425
  duck = Crack::XML.parse(xml)
467
- duck[duck.keys[0]]['type'] = duck.keys[0]
426
+ duck[duck.keys[0]]["type"] = duck.keys[0]
468
427
  duck = duck[duck.keys[0]]
469
428
  transaction_listener.apply(duck)
470
429
  reader.next
@@ -476,24 +435,24 @@ module LitleOnline
476
435
  return @path_to_batches
477
436
  end
478
437
 
479
- # Called when you wish to finish adding batches to your request, this method
480
- # rewrites the aggregate batch file to the final LitleRequest xml doc
481
- # with the appropos LitleRequest tags.
438
+ # Called when you wish to finish adding batches to your request, this method rewrites the aggregate
439
+ # batch file to the final LitleRequest xml doc with the appropos LitleRequest tags.
482
440
  def finish_request
441
+
483
442
  File.open(@path_to_request, 'w') do |f|
484
- # jam dat header in there
443
+ #jam dat header in there
485
444
  f.puts(build_request_header())
486
- # read into the request file from the batches file
445
+ #read into the request file from the batches file
487
446
  File.foreach(@path_to_batches) do |li|
488
447
  f.puts li
489
448
  end
490
- # finally, let's poot in a header, for old time's sake
449
+ #finally, let's poot in a header, for old time's sake
491
450
  f.puts '</litleRequest>'
492
451
  end
493
452
 
494
- # rename the requests file
495
- File.rename(@path_to_request, @path_to_request + '.complete')
496
- # we don't need the master batch file anymore
453
+ #rename the requests file
454
+ File.rename(@path_to_request, @path_to_request + COMPLETE_FILE_SUFFIX)
455
+ #we don't need the master batch file anymore
497
456
  File.delete(@path_to_batches)
498
457
  end
499
458
 
@@ -507,14 +466,13 @@ module LitleOnline
507
466
  authentication.password = get_config(:password, options)
508
467
 
509
468
  litle_request.authentication = authentication
510
- litle_request.version = '9.14'
511
- litle_request.xmlns = 'http://www.litle.com/schema'
512
- # litle_request.id = options['sessionId']
513
- # grab from options; okay if nil
469
+ litle_request.version = '11.4'
470
+ litle_request.xmlns = "http://www.litle.com/schema"
471
+ # litle_request.id = options['sessionId'] #grab from options; okay if nil
514
472
  litle_request.numBatchRequests = @num_batch_requests
515
473
 
516
474
  xml = litle_request.save_to_xml.to_s
517
- xml[/<\/litleRequest>/] = ''
475
+ xml[/<\/litleRequest>/]=''
518
476
  return xml
519
477
  end
520
478
 
@@ -527,5 +485,176 @@ module LitleOnline
527
485
  return options[field]
528
486
  end
529
487
  end
488
+
489
+ def delete_files_in_path(path, pattern)
490
+ Dir.foreach(path) do |filename|
491
+ if((filename =~ pattern)) != nil then
492
+ File.delete(path + filename)
493
+ end
494
+ end
495
+ end
496
+
497
+ def prepare_for_sftp(path, use_encryption)
498
+ if(path[-1,1] != '/' && path[-1,1] != '\\') then
499
+ path = path + File::SEPARATOR
500
+ end
501
+
502
+ if(!File.directory?(path)) then
503
+ Dir.mkdir(path)
504
+ end
505
+
506
+ if use_encryption
507
+ encrypted_path = path + ENCRYPTED_PATH_DIR
508
+ if !File.directory?(encrypted_path)
509
+ Dir.mkdir(encrypted_path)
510
+ end
511
+ end
512
+ return path
513
+ end
514
+
515
+
516
+ def encrypt_request_files(path, encrypted_path, options)
517
+ Dir.foreach(path) do |filename|
518
+ if (filename =~ /#{REQUEST_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}\z/) != nil
519
+ cipher_filename = encrypted_path + filename + ENCRYPTED_FILE_SUFFIX
520
+ plain_filename = path + filename
521
+ encrypt_batch_file_request(cipher_filename, plain_filename, options)
522
+ end
523
+ end
524
+ end
525
+
526
+
527
+ def decrypt_response_files(response_path, args)
528
+ delete_batch_files = get_config(SFTP_DELETE_BATCH_FILES_CONFIG_NAME, args)
529
+
530
+ Dir.foreach(response_path) do |filename|
531
+ if (filename =~ /#{RESPONSE_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}#{ENCRYPTED_FILE_SUFFIX}.asc#{RECEIVED_FILE_SUFFIX}\z/) != nil
532
+ decrypt_batch_file_response(response_path + filename, args)
533
+ end
534
+ end
535
+ if delete_batch_files
536
+ delete_files_in_path(response_path, /#{RESPONSE_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}#{ENCRYPTED_FILE_SUFFIX}.asc#{RECEIVED_FILE_SUFFIX}\z/)
537
+ end
538
+ end
539
+
540
+
541
+ def upload_to_sftp(path_to_requests, url, username, password, use_encryption)
542
+ begin
543
+ responses_expected = 0
544
+ Net::SFTP.start(url, username, :password => password) do |sftp|
545
+ Dir.foreach(path_to_requests) do |filename|
546
+ if (filename =~ /#{REQUEST_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}((#{ENCRYPTED_FILE_SUFFIX})?)\z/) != nil
547
+ new_filename = filename + '.prg'
548
+ File.rename(path_to_requests + filename, path_to_requests + new_filename)
549
+ # upload the file
550
+ sftp.upload!(path_to_requests + new_filename, '/inbound/' + new_filename)
551
+ responses_expected += 1
552
+ # rename now that we're done
553
+ sftp.rename!('/inbound/'+ new_filename, '/inbound/' + new_filename.gsub('prg', 'asc'))
554
+ File.rename(path_to_requests + new_filename, path_to_requests + new_filename.gsub('prg','sent'))
555
+ if use_encryption
556
+ # rename the plain text file too
557
+ text_filename = (path_to_requests + filename).gsub(ENCRYPTED_PATH_DIR, '').gsub(ENCRYPTED_FILE_SUFFIX, '')
558
+ File.rename(text_filename, text_filename + SENT_FILE_SUFFIX)
559
+ end
560
+ end
561
+ end
562
+ end
563
+ return responses_expected
564
+ rescue Net::SSH::AuthenticationFailed
565
+ raise ArgumentError, "The sFTP credentials provided were incorrect. Try again!"
566
+ end
567
+ end
568
+
569
+
570
+ def download_from_sftp(response_path, url, username, password)
571
+ responses_grabbed = 0
572
+ begin
573
+ #wait until a response has a possibility of being there
574
+ sleep(@POLL_DELAY)
575
+ time_begin = Time.now
576
+ Net::SFTP.start(url, username, :password => password) do |sftp|
577
+ while((Time.now - time_begin) < @RESPONSE_TIME_OUT && responses_grabbed < @responses_expected)
578
+ #sleep for 60 seconds, ¿no es bueno?
579
+ sleep(60)
580
+ sftp.dir.foreach('/outbound/') do |entry|
581
+ if (entry.name =~ /#{REQUEST_FILE_PREFIX}\d+#{COMPLETE_FILE_SUFFIX}((#{ENCRYPTED_FILE_SUFFIX})?).asc\z/) != nil then
582
+ response_filename = response_path + entry.name.gsub(REQUEST_FILE_PREFIX, RESPONSE_FILE_PREFIX) + RECEIVED_FILE_SUFFIX
583
+ sftp.download!('/outbound/' + entry.name, response_filename)
584
+ responses_grabbed += 1
585
+ 3.times{
586
+ begin
587
+ sftp.remove!('/outbound/' + entry.name)
588
+ break
589
+ rescue Net::SFTP::StatusException
590
+ #try, try, try again
591
+ puts "We couldn't remove it! Try again"
592
+ end
593
+ }
594
+ end
595
+ end
596
+ end
597
+ if responses_grabbed < @responses_expected then
598
+ raise RuntimeError, "We timed out in waiting for a response from the server. :("
599
+ end
600
+ end
601
+ rescue Net::SSH::AuthenticationFailed
602
+ raise ArgumentError, "The sFTP credentials provided were incorrect. Try again!"
603
+ end
604
+ end
605
+
606
+ # Encrypt the request file for a PGP enabled account
607
+ # +cipher_filename+:: Name of File that would contain encrypted batch
608
+ # +plain_filename+:: Name of File containing batch in XML markup
609
+ # +options+:: An (option) +Hash+ containing the public key to attempt to encrypt the file.
610
+ # If not provided, the values will be populated from the configuration file.
611
+ def encrypt_batch_file_request(cipher_filename, plain_filename, options)
612
+ pgpkeyID = get_config(:vantivPublicKeyID, options)
613
+ if pgpkeyID == ""
614
+ raise RuntimeError, "The public key to encrypt batch file requests is missing from the config"
615
+ end
616
+
617
+ IOStreams::Pgp::Writer.open(
618
+ cipher_filename,
619
+ recipient: pgpkeyID
620
+ ) do |output|
621
+ File.open(plain_filename, "r").readlines.each do |line|
622
+ output.puts(line)
623
+ end
624
+ end
625
+
626
+ rescue IOStreams::Pgp::Failure => e
627
+ raise ArgumentError, "Please check if you have entered correct vantivePublicKeyID to config and that " +
628
+ "vantiv's public key is added to your gpg keyring and is trusted. #{e.message}"
629
+ end
630
+
631
+ # Decrypt the encrypted batch response file
632
+ # +response_filename+:: Filename of encrypted batch response file
633
+ # The decrypted response would be placed in +response_filename+.gsub("encrypted", "")
634
+ # +args+:: An (arg) +Hash+ containing the passphrase to atempt to decrypt the file
635
+ # If not provided, the values will be populated from the configuration file.
636
+ def decrypt_batch_file_response(response_filename, args)
637
+ passphrase = get_config(:passphrase, args)
638
+ delete_batch_files = get_config(:deleteBatchFiles, args)
639
+ if passphrase == ""
640
+ raise RuntimeError, "The passphrase to decrypt the batch file responses is missing from the config"
641
+ end
642
+ decrypted_response_filename = response_filename.gsub('/encrypted', '').gsub(".encrypted", "")
643
+
644
+ decrypted_file = File.open(decrypted_response_filename, "w")
645
+ IOStreams::Pgp::Reader.open(
646
+ response_filename,
647
+ passphrase: passphrase
648
+ ) do |stream|
649
+ while !stream.eof?
650
+ decrypted_file.puts(stream.readline())
651
+ #puts stream.readline()
652
+ end
653
+ end
654
+ decrypted_file.close()
655
+ rescue IOStreams::Pgp::Failure => e
656
+ raise ArgumentError, "Please check if you have entered correct passphrase to config and that your " +
657
+ "merchant private key is added to your gpg keyring and is trusted. #{e.message}"
658
+ end
530
659
  end
531
660
  end