LitleOnline 8.19.0 → 8.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +5 -13
  2. data/CHANGELOG +34 -0
  3. data/README.md +1 -1
  4. data/Rakefile +2 -2
  5. data/bin/Setup.rb +16 -6
  6. data/lib/LitleBatchRequest.rb +85 -2
  7. data/lib/LitleOnlineRequest.rb +108 -5
  8. data/lib/LitleRequest.rb +14 -9
  9. data/lib/LitleTransaction.rb +152 -3
  10. data/lib/XMLFields.rb +441 -7
  11. data/test/functional/test_activate.rb +100 -0
  12. data/test/functional/test_activateReversal.rb +56 -0
  13. data/test/functional/test_auth.rb +38 -1
  14. data/test/functional/test_balanceInquiry.rb +80 -0
  15. data/test/functional/test_batchStream.rb +145 -0
  16. data/test/functional/test_cancelSubscription.rb +55 -0
  17. data/test/functional/test_captureGivenAuth.rb +32 -2
  18. data/test/functional/test_createPlan.rb +85 -0
  19. data/test/functional/test_credit.rb +22 -1
  20. data/test/functional/test_deactivate.rb +80 -0
  21. data/test/functional/test_deactivateReversal.rb +56 -0
  22. data/test/functional/test_depositReversal.rb +56 -0
  23. data/test/functional/test_forceCapture.rb +23 -1
  24. data/test/functional/test_litle_requests.rb +3 -2
  25. data/test/functional/test_load.rb +82 -0
  26. data/test/functional/test_loadReversal.rb +56 -0
  27. data/test/functional/test_refundReversal.rb +56 -0
  28. data/test/functional/test_sale.rb +23 -1
  29. data/test/functional/test_unload.rb +82 -0
  30. data/test/functional/test_unloadReversal.rb +56 -0
  31. data/test/functional/test_updatePlan.rb +58 -0
  32. data/test/functional/test_updateSubscription.rb +76 -0
  33. data/test/functional/ts_all.rb +21 -2
  34. data/test/unit/test_LitleBatchRequest.rb +47 -2
  35. data/test/unit/test_LitleOnlineRequest.rb +2 -2
  36. data/test/unit/test_activate.rb +92 -0
  37. data/test/{functional/ts_all.rb~ → unit/test_activateReversal.rb} +17 -17
  38. data/test/unit/test_auth.rb +37 -3
  39. data/test/unit/test_balanceInquiry.rb +52 -0
  40. data/test/unit/test_cancelSubscription.rb +43 -0
  41. data/test/unit/test_captureGivenAuth.rb +44 -2
  42. data/test/unit/test_createPlan.rb +52 -0
  43. data/test/unit/test_credit.rb +3 -2
  44. data/test/unit/test_deactivate.rb +52 -0
  45. data/test/unit/test_deactivateReversal.rb +44 -0
  46. data/test/unit/test_depositReversal.rb +44 -0
  47. data/test/unit/test_load.rb +53 -0
  48. data/test/unit/test_loadReversal.rb +44 -0
  49. data/test/unit/test_refundReversal.rb +44 -0
  50. data/test/unit/test_sale.rb +18 -1
  51. data/test/unit/test_unload.rb +53 -0
  52. data/test/unit/test_unloadReversal.rb +44 -0
  53. data/test/unit/test_updatePlan.rb +45 -0
  54. data/test/unit/test_updateSubscription.rb +172 -0
  55. data/test/unit/test_xmlfields.rb +395 -0
  56. data/test/unit/ts_unit.rb +19 -2
  57. metadata +51 -34
  58. data/CHANGELOG~ +0 -81
  59. data/Rakefile~ +0 -93
  60. data/lib/LitleOnlineRequest.rb~ +0 -198
  61. data/lib/LitleRequest.rb~ +0 -513
  62. data/lib/LitleTransaction.rb~ +0 -297
  63. data/lib/XMLFields.rb~ +0 -1380
  64. data/test/unit/test_LitleOnlineRequest.rb~ +0 -296
  65. data/test/unit/test_sale.rb~ +0 -390
  66. data/test/unit/test_xmlfields.rb~ +0 -2515
@@ -1,198 +0,0 @@
1
- =begin
2
- Copyright (c) 2011 Litle & Co.
3
-
4
- Permission is hereby granted, free of charge, to any person
5
- obtaining a copy of this software and associated documentation
6
- files (the "Software"), to deal in the Software without
7
- restriction, including without limitation the rights to use,
8
- copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the
10
- Software is furnished to do so, subject to the following
11
- conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
- OTHER DEALINGS IN THE SOFTWARE.
24
- =end
25
- require_relative 'Configuration'
26
-
27
- #
28
- # This class handles sending the Litle online request
29
- #
30
- module LitleOnline
31
-
32
- class LitleOnlineRequest
33
- def initialize
34
- #load configuration data
35
- @config_hash = Configuration.new.config
36
- @litle_transaction = LitleTransaction.new
37
- end
38
-
39
- def authorization(options)
40
- transaction = @litle_transaction.authorization(options)
41
-
42
- commit(transaction, :authorization, options)
43
- end
44
-
45
- def sale(options)
46
- transaction = @litle_transaction.sale(options)
47
-
48
- commit(transaction, :sale, options)
49
- end
50
-
51
- def auth_reversal(options)
52
- transaction = @litle_transaction.auth_reversal(options)
53
-
54
- commit(transaction, :authReversal, options)
55
- end
56
-
57
- def credit(options)
58
- transaction = @litle_transaction.credit(options)
59
-
60
- commit(transaction, :credit, options)
61
- end
62
-
63
- def register_token_request(options)
64
- transaction = @litle_transaction.register_token_request(options)
65
-
66
- commit(transaction, :registerTokenRequest, options)
67
- end
68
-
69
- def update_card_validation_num_on_token(options)
70
- transaction = @litle_transaction.update_card_validation_num_on_token(options)
71
-
72
- commit(transaction, :updateCardValidationNumOnToken, options)
73
- end
74
-
75
- def force_capture(options)
76
- transaction = @litle_transaction.force_capture(options)
77
-
78
- commit(transaction, :forceCapture, options)
79
- end
80
-
81
- def capture(options)
82
- transaction = @litle_transaction.capture(options)
83
-
84
- commit(transaction, :captureTxn, options)
85
- end
86
-
87
- def capture_given_auth(options)
88
- transaction = @litle_transaction.capture_given_auth(options)
89
-
90
- commit(transaction, :captureGivenAuth, options)
91
- end
92
-
93
- def void(options)
94
- transaction = @litle_transaction.void(options)
95
-
96
- commit(transaction, :void, options)
97
- end
98
-
99
- def echeck_redeposit(options)
100
- transaction = @litle_transaction.echeck_redeposit(options)
101
-
102
- commit(transaction, :echeckRedeposit, options)
103
- end
104
-
105
- def echeck_sale(options)
106
- transaction = @litle_transaction.echeck_sale(options)
107
-
108
- commit(transaction, :echeckSale, options)
109
- end
110
-
111
- def echeck_credit(options)
112
- transaction = @litle_transaction.echeck_credit(options)
113
-
114
- begin
115
- commit(transaction, :echeckCredit, options)
116
- rescue XML::MappingError => e
117
- response = LitleOnlineResponse.new
118
- response.message = "The content of element 'echeckCredit' is not complete"
119
- return response
120
- end
121
- end
122
-
123
- def echeck_verification(options)
124
- transaction = @litle_transaction.echeck_verification(options)
125
-
126
- commit(transaction, :echeckVerification, options)
127
- end
128
-
129
- def echeck_void(options)
130
- transaction = @litle_transaction.echeck_void(options)
131
-
132
- commit(transaction, :echeckVoid, options)
133
- end
134
-
135
- private
136
-
137
- def add_account_info(transaction, options)
138
- transaction.reportGroup = get_report_group(options)
139
- transaction.transactionId = options['id']
140
- transaction.customerId = options['customerId']
141
- end
142
-
143
- def build_request(options)
144
- request = OnlineRequest.new
145
-
146
- authentication = Authentication.new
147
- authentication.user = get_config(:user, options)
148
- authentication.password = get_config(:password, options)
149
-
150
- request.authentication = authentication
151
- request.merchantId = get_merchant_id(options)
152
- request.version = '8.18'
153
- request.loggedInUser = get_logged_in_user(options)
154
- request.xmlns = "http://www.litle.com/schema"
155
- request.merchantSdk = get_merchant_sdk(options)
156
-
157
- request
158
- end
159
-
160
- def commit(transaction, type, options)
161
- configure_connection(options)
162
-
163
- request = build_request(options)
164
-
165
- add_account_info(transaction, options)
166
- request.send(:"#{type}=", transaction)
167
-
168
- xml = request.save_to_xml.to_s
169
- LitleXmlMapper.request(xml, @config_hash)
170
- end
171
-
172
- def configure_connection(options={})
173
- @config_hash['proxy_addr'] = options['proxy_addr'] unless options['proxy_addr'].nil?
174
- @config_hash['proxy_port'] = options['proxy_port'] unless options['proxy_port'].nil?
175
- @config_hash['url'] = options['url'] unless options['url'].nil?
176
- end
177
-
178
- def get_merchant_id(options)
179
- options['merchantId'] || @config_hash['currency_merchant_map']['DEFAULT']
180
- end
181
-
182
- def get_merchant_sdk(options)
183
- options['merchantSdk'] || 'Ruby;8.18.0'
184
- end
185
-
186
- def get_report_group(options)
187
- options['reportGroup'] || @config_hash['default_report_group']
188
- end
189
-
190
- def get_config(field, options)
191
- options[field.to_s] == nil ? @config_hash[field.to_s] : options[field.to_s]
192
- end
193
-
194
- def get_logged_in_user(options)
195
- options['loggedInUser'] || nil
196
- end
197
- end
198
- end
data/lib/LitleRequest.rb~ DELETED
@@ -1,513 +0,0 @@
1
- =begin
2
- Copyright (c) 2011 Litle & Co.
3
-
4
- Permission is hereby granted, free of charge, to any person
5
- obtaining a copy of this software and associated documentation
6
- files (the "Software"), to deal in the Software without
7
- restriction, including without limitation the rights to use,
8
- copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the
10
- Software is furnished to do so, subject to the following
11
- conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
- OTHER DEALINGS IN THE SOFTWARE.
24
- =end
25
- require_relative 'Configuration'
26
- require 'net/sftp'
27
- require 'libxml'
28
- require 'crack/xml'
29
- require 'socket'
30
-
31
- include Socket::Constants
32
- #
33
- # This class handles sending the Litle Request (which is actually a series of batches!)
34
- #
35
-
36
- module LitleOnline
37
- class LitleRequest
38
- include XML::Mapping
39
- def initialize(options = {})
40
- #load configuration data
41
- @config_hash = Configuration.new.config
42
- @num_batch_requests = 0
43
- @path_to_request = ""
44
- @path_to_batches = ""
45
- @num_total_transactions = 0
46
- @MAX_NUM_TRANSACTIONS = 500000
47
- @options = options
48
- # current time out set to 2 mins
49
- # this value is in seconds
50
- @RESPONSE_TIME_OUT = 360
51
- @POLL_DELAY = 0
52
- @responses_expected = 0
53
- end
54
-
55
- # Creates the necessary files for the LitleRequest at the path specified. path/request_(TIMESTAMP) will be
56
- # the final XML markup and path/request_(TIMESTAMP) will hold intermediary XML markup
57
- # Params:
58
- # +path+:: A +String+ containing the path to the folder on disc to write the files to
59
- def create_new_litle_request(path)
60
- ts = Time::now.to_i.to_s
61
- begin
62
- ts += Time::now.nsec.to_s
63
- rescue NoMethodError # ruby 1.8.7 fix
64
- ts += Time::now.usec.to_s
65
- end
66
-
67
- if(File.file?(path)) then
68
- raise RuntimeError, "Entered a file not a path."
69
- end
70
-
71
- if(path[-1,1] != '/' and path[-1,1] != '\\') then
72
- path = path + File::SEPARATOR
73
- end
74
-
75
- if !File.directory?(path) then
76
- Dir.mkdir(path)
77
- end
78
-
79
- @path_to_request = path + 'request_' + ts
80
- @path_to_batches = @path_to_request + '_batches'
81
-
82
- if File.file?(@path_to_request) or File.file?(@path_to_batches) then
83
- create_new_litle_request(path)
84
- return
85
- end
86
-
87
- File.open(@path_to_request, 'a+') do |file|
88
- file.write("")
89
- end
90
- File.open(@path_to_batches, 'a+') do |file|
91
- file.write("")
92
- end
93
- end
94
-
95
- # Adds a batch to the LitleRequest. If the batch is open when passed, it will be closed prior to being added.
96
- # Params:
97
- # +arg+:: a +LitleBatchRequest+ containing the transactions you wish to send or a +String+ specifying the
98
- # path to the batch file
99
- def commit_batch(arg)
100
- path_to_batch = ""
101
- #they passed a batch
102
- if arg.kind_of?(LitleBatchRequest) then
103
- path_to_batch = arg.get_batch_name
104
- if((au = arg.get_au_batch) != nil) then
105
- # also commit the account updater batch
106
- commit_batch(au)
107
- end
108
- elsif arg.kind_of?(LitleAUBatch) then
109
- path_to_batch = arg.get_batch_name
110
- elsif arg.kind_of?(String) then
111
- path_to_batch = arg
112
- else
113
- raise RuntimeError, "You entered neither a path nor a batch. Game over :("
114
- end
115
- #the batch isn't closed. let's help a brother out
116
- if (ind = path_to_batch.index(/\.closed/)) == nil then
117
- if arg.kind_of?(String) then
118
- new_batch = LitleBatchRequest.new
119
- new_batch.open_existing_batch(path_to_batch)
120
- new_batch.close_batch()
121
- path_to_batch = new_batch.get_batch_name
122
- # if we passed a path to an AU batch, then new_batch will be a new, empty batch and the batch we passed
123
- # will be in the AU batch variable. thus, we wanna grab that file name and remove the empty batch.
124
- if(new_batch.get_au_batch != nil) then
125
- File.remove(path_to_batch)
126
- path_to_batch = new_batch.get_au_batch.get_batch_name
127
- end
128
- elsif arg.kind_of?(LitleBatchRequest) then
129
- arg.close_batch()
130
- path_to_batch = arg.get_batch_name
131
- elsif arg.kind_of?(LitleAUBatch) then
132
- arg.close_batch()
133
- path_to_batch = arg.get_batch_name
134
- end
135
- ind = path_to_batch.index(/\.closed/)
136
- end
137
- transactions_in_batch = path_to_batch[ind+8..path_to_batch.length].to_i
138
-
139
- # if the litle request would be too big, let's make another!
140
- if (@num_total_transactions + transactions_in_batch) > @MAX_NUM_TRANSACTIONS then
141
- finish_request
142
- initialize(@options)
143
- create_new_litle_request
144
- else #otherwise, let's add it line by line to the request doc
145
- @num_batch_requests += 1
146
- #how long we wnat to wait around for the FTP server to get us a response
147
- @RESPONSE_TIME_OUT += 90 + (transactions_in_batch * 0.25)
148
- #don't start looking until there could possibly be a response
149
- @POLL_DELAY += 30 +(transactions_in_batch * 0.02)
150
- @num_total_transactions += transactions_in_batch
151
-
152
- File.open(@path_to_batches, 'a+') do |fo|
153
- File.foreach(path_to_batch) do |li|
154
- fo.puts li
155
- end
156
- end
157
-
158
- File.delete(path_to_batch)
159
- end
160
- end
161
-
162
- # Adds an RFRRequest to the LitleRequest.
163
- # params:
164
- # +options+:: a required +Hash+ containing configuration info for the RFRRequest. If the RFRRequest is for a batch, then the
165
- # litleSessionId is required as a key/val pair. If the RFRRequest is for account updater, then merchantId and postDay are required
166
- # as key/val pairs.
167
- # +path+:: optional path to save the new litle request containing the RFRRequest at
168
- def add_rfr_request(options, path = (File.dirname(@path_to_batches)))
169
-
170
- rfrrequest = LitleRFRRequest.new
171
- if(options['litleSessionId'] != nil) then
172
- rfrrequest.litleSessionId = options['litleSessionId']
173
- elsif(options['merchantId'] != nil and options['postDay'] != nil) then
174
- accountUpdate = AccountUpdateFileRequestData.new
175
- accountUpdate.merchantId = options['merchantId']
176
- accountUpdate.postDay = options['postDay']
177
- rfrrequest.accountUpdateFileRequestData = accountUpdate
178
- else
179
- raise ArgumentError, "For an RFR Request, you must specify either a litleSessionId for an RFRRequest for batch or a merchantId
180
- and a postDay for an RFRRequest for account updater."
181
- end
182
-
183
- litleRequest = LitleRequestForRFR.new
184
- litleRequest.rfrRequest = rfrrequest
185
-
186
- authentication = Authentication.new
187
- authentication.user = get_config(:user, options)
188
- authentication.password = get_config(:password, options)
189
-
190
- litleRequest.authentication = authentication
191
- litleRequest.numBatchRequests = "0"
192
-
193
- litleRequest.version = '8.18'
194
- litleRequest.xmlns = "http://www.litle.com/schema"
195
-
196
-
197
- xml = litleRequest.save_to_xml.to_s
198
-
199
- ts = Time::now.to_i.to_s
200
- begin
201
- ts += Time::now.nsec.to_s
202
- rescue NoMethodError # ruby 1.8.7 fix
203
- ts += Time::now.usec.to_s
204
- end
205
- if(File.file?(path)) then
206
- raise RuntimeError, "Entered a file not a path."
207
- end
208
-
209
- if(path[-1,1] != '/' and path[-1,1] != '\\') then
210
- path = path + File::SEPARATOR
211
- end
212
-
213
- if !File.directory?(path) then
214
- Dir.mkdir(path)
215
- end
216
-
217
- path_to_request = path + 'request_' + ts
218
-
219
- File.open(path_to_request, 'a+') do |file|
220
- file.write xml
221
- end
222
- File.rename(path_to_request, path_to_request + '.complete')
223
- @RESPONSE_TIME_OUT += 90
224
- end
225
-
226
- # FTPs all previously unsent LitleRequests located in the folder denoted by path to the server
227
- # Params:
228
- # +path+:: A +String+ containing the path to the folder on disc where LitleRequests are located.
229
- # This should be the same location where the LitleRequests were written to. If no path is explicitly
230
- # provided, then we use the directory where the current working batches file is stored.
231
- # +options+:: An (option) +Hash+ containing the username, password, and URL to attempt to sFTP to.
232
- # If not provided, the values will be populated from the configuration file.
233
- def send_to_litle(path = (File.dirname(@path_to_batches)), options = {})
234
- username = get_config(:sftp_username, options)
235
- password = get_config(:sftp_password, options)
236
- url = get_config(:sftp_url, options)
237
- if(username == nil or password == nil or url == nil) then
238
- raise ArgumentError, "You are not configured to use sFTP for batch processing. Please run /bin/Setup.rb again!"
239
- end
240
-
241
- if(path[-1,1] != '/' && path[-1,1] != '\\') then
242
- path = path + File::SEPARATOR
243
- end
244
-
245
- begin
246
- Net::SFTP.start(url, username, :password => password) do |sftp|
247
- # our folder is /SHORTNAME/SHORTNAME/INBOUND
248
- Dir.foreach(path) do |filename|
249
- #we have a complete report according to filename regex
250
- if((filename =~ /request_\d+.complete\z/) != nil) then
251
- # adding .prg extension per the XML
252
- File.rename(path + filename, path + filename + '.prg')
253
- end
254
- end
255
-
256
- @responses_expected = 0
257
- Dir.foreach(path) do |filename|
258
- if((filename =~ /request_\d+.complete.prg\z/) != nil) then
259
- # upload the file
260
- sftp.upload!(path + filename, '/inbound/' + filename)
261
- @responses_expected += 1
262
- # rename now that we're done
263
- sftp.rename!('/inbound/'+ filename, '/inbound/' + filename.gsub('prg', 'asc'))
264
- File.rename(path + filename, path + filename.gsub('prg','sent'))
265
- end
266
- end
267
- end
268
- rescue Net::SSH::AuthenticationFailed
269
- raise ArgumentError, "The sFTP credentials provided were incorrect. Try again!"
270
- end
271
- end
272
-
273
- # Sends all previously unsent LitleRequests in the specified directory to the Litle server
274
- # by use of fast batch. All results will be written to disk as we get them. Note that use
275
- # of fastbatch is strongly discouraged!
276
- def send_to_litle_stream(options = {}, path = (File.dirname(@path_to_batches)))
277
- url = get_config(:fast_url, options)
278
- port = get_config(:fast_port, options)
279
-
280
- if(url == nil or url == "") then
281
- raise ArgumentError, "A URL for fastbatch was not specified in the config file or passed options. Reconfigure and try again."
282
- end
283
-
284
- if(port == "" or port == nil) then
285
- raise ArgumentError, "A port number for fastbatch was not specified in the config file or passed options. Reconfigure and try again."
286
- end
287
-
288
- if(path[-1,1] != '/' && path[-1,1] != '\\') then
289
- path = path + File::SEPARATOR
290
- end
291
-
292
- if (!File.directory?(path + 'responses/')) then
293
- Dir.mkdir(path + 'responses/')
294
- end
295
-
296
- Dir.foreach(path) do |filename|
297
- if((filename =~ /request_\d+.complete\z/) != nil) then
298
- begin
299
- socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
300
- sockaddr = Socket.pack_sockaddr_in( port.to_i, url )
301
- socket.connect( sockaddr )
302
- rescue => e
303
- raise "A connection couldn't be established. Are you sure you have the correct credentials? Exception: " + e.message
304
- end
305
-
306
- File.foreach(path + filename) do |li|
307
- socket.write(li)
308
- end
309
- File.rename(path + filename, path + filename + '.sent')
310
- File.open(path + 'responses/' + (filename + '.asc.received').gsub("request", "response"), 'a+') do |fo|
311
- fo.puts(socket.read)
312
- end
313
-
314
- end
315
- end
316
- end
317
-
318
-
319
- # Grabs response files over SFTP from Litle.
320
- # Params:
321
- # +args+:: An (optional) +Hash+ containing values for the number of responses expected, the
322
- # path to the folder on disk to write the responses from the Litle server to, the username and
323
- # password with which to connect ot the sFTP server, and the URL to connect over sFTP. Values not
324
- # provided in the hash will be populate automatically based on our best guess
325
- def get_responses_from_server(args = {})
326
- @responses_expected = args[:responses_expected] ||= @responses_expected
327
- response_path = args[:response_path] ||= (File.dirname(@path_to_batches) + '/responses/')
328
- username = get_config(:sftp_username, args)
329
- password = get_config(:sftp_password, args)
330
- url = get_config(:sftp_url, args)
331
-
332
- if(username == nil or password == nil or url == nil) then
333
- raise ConfigurationException, "You are not configured to use sFTP for batch processing. Please run /bin/Setup.rb again!"
334
- end
335
-
336
- if(response_path[-1,1] != '/' && response_path[-1,1] != '\\') then
337
- response_path = response_path + File::SEPARATOR
338
- end
339
-
340
- if(!File.directory?(response_path)) then
341
- Dir.mkdir(response_path)
342
- end
343
- begin
344
- responses_grabbed = 0
345
- Net::SFTP.start(url, username, :password => password) do |sftp|
346
- # clear out the sFTP outbound dir prior to checking for new files, avoids leaving files on the server
347
- # if files are left behind we are not counting then towards the expected total
348
- sftp.dir.foreach('/outbound/') do |entry|
349
- if((entry.name =~ /request_\d+.complete.asc\z/) != nil) then
350
- sftp.download!('/outbound/' + entry.name, response_path + entry.name.gsub('request', 'response') + '.received')
351
- 3.times{
352
- begin
353
- sftp.remove!('/outbound/' + entry.name)
354
- break
355
- rescue Net::SFTP::StatusException
356
- #try, try, try again
357
- puts "We couldn't remove it! Try again"
358
- end
359
- }
360
- end
361
- end
362
- end
363
- #wait until a response has a possibility of being there
364
- sleep(@POLL_DELAY)
365
- time_begin = Time.now
366
- Net::SFTP.start(url, username, :password => password) do |sftp|
367
- while((Time.now - time_begin) < @RESPONSE_TIME_OUT && responses_grabbed < @responses_expected)
368
- #sleep for 60 seconds, ¿no es bueno?
369
- sleep(60)
370
- sftp.dir.foreach('/outbound/') do |entry|
371
- if((entry.name =~ /request_\d+.complete.asc\z/) != nil) then
372
- sftp.download!('/outbound/' + entry.name, response_path + entry.name.gsub('request', 'response') + '.received')
373
- responses_grabbed += 1
374
- 3.times{
375
- begin
376
- sftp.remove!('/outbound/' + entry.name)
377
- break
378
- rescue Net::SFTP::StatusException
379
- #try, try, try again
380
- puts "We couldn't remove it! Try again"
381
- end
382
- }
383
- end
384
- end
385
- end
386
- #if our timeout timed out, we're having problems
387
- if responses_grabbed < @responses_expected then
388
- raise RuntimeError, "We timed out in waiting for a response from the server. :("
389
- end
390
- end
391
- rescue Net::SSH::AuthenticationFailed
392
- raise ArgumentError, "The sFTP credentials provided were incorrect. Try again!"
393
- end
394
- end
395
-
396
- # Params:
397
- # +args+:: A +Hash+ containing arguments for the processing process. This hash MUST contain an entry
398
- # for a transaction listener (see +DefaultLitleListener+). It may also include a batch listener and a
399
- # custom path where response files from the server are located (if it is not provided, we'll guess the position)
400
- def process_responses(args)
401
- #the transaction listener is required
402
- if(!args.has_key?(:transaction_listener)) then
403
- raise ArgumentError, "The arguments hash must contain an entry for transaction listener!"
404
- end
405
-
406
- transaction_listener = args[:transaction_listener]
407
- batch_listener = args[:batch_listener] ||= nil
408
- path_to_responses = args[:path_to_responses] ||= (File.dirname(@path_to_batches) + '/responses/')
409
-
410
- Dir.foreach(path_to_responses) do |filename|
411
- if ((filename =~ /response_\d+.complete.asc.received\z/) != nil) then
412
- process_response(path_to_responses + filename, transaction_listener, batch_listener)
413
- File.rename(path_to_responses + filename, path_to_responses + filename + '.processed')
414
- end
415
- end
416
- end
417
-
418
- # Params:
419
- # +path_to_response+:: The path to a specific .asc file to process
420
- # +transaction_listener+:: A listener to be applied to the hash of each transaction
421
- # (see +DefaultLitleListener+)
422
- # +batch_listener+:: An (optional) listener to be applied to the hash of each batch.
423
- # Note that this will om-nom-nom quite a bit of memory
424
- def process_response(path_to_response, transaction_listener, batch_listener = nil)
425
- reader = LibXML::XML::Reader.file(path_to_response)
426
- reader.read # read into the root node
427
- #if the response attribute is nil, we're dealing with an RFR and everything is a-okay
428
- if reader.get_attribute('response') != "0" and reader.get_attribute('response') != nil then
429
- raise RuntimeError, "Error parsing Litle Request: " + reader.get_attribute("message")
430
- end
431
-
432
- reader.read
433
- count = 0
434
- while true and count < 500001 do
435
-
436
- count += 1
437
- if(reader.node == nil) then
438
- return false
439
- end
440
-
441
- case reader.node.name.to_s
442
- when "batchResponse"
443
- reader.read
444
- when "litleResponse"
445
- return false
446
- when "text"
447
- reader.read
448
- else
449
- xml = reader.read_outer_xml
450
- duck = Crack::XML.parse(xml)
451
- duck[duck.keys[0]]["type"] = duck.keys[0]
452
- duck = duck[duck.keys[0]]
453
- transaction_listener.apply(duck)
454
- reader.next
455
- end
456
- end
457
- end
458
-
459
- def get_path_to_batches
460
- return @path_to_batches
461
- end
462
-
463
- # Called when you wish to finish adding batches to your request, this method rewrites the aggregate
464
- # batch file to the final LitleRequest xml doc with the appropos LitleRequest tags.
465
- def finish_request
466
- File.open(@path_to_request, 'w') do |f|
467
- #jam dat header in there
468
- f.puts(build_request_header())
469
- #read into the request file from the batches file
470
- File.foreach(@path_to_batches) do |li|
471
- f.puts li
472
- end
473
- #finally, let's poot in a header, for old time's sake
474
- f.puts '</litleRequest>'
475
- end
476
-
477
- #rename the requests file
478
- File.rename(@path_to_request, @path_to_request + '.complete')
479
- #we don't need the master batch file anymore
480
- File.delete(@path_to_batches)
481
- end
482
-
483
- private
484
-
485
- def build_request_header(options = @options)
486
- litle_request = self
487
-
488
- authentication = Authentication.new
489
- authentication.user = get_config(:user, options)
490
- authentication.password = get_config(:password, options)
491
-
492
- litle_request.authentication = authentication
493
- litle_request.version = '8.18'
494
- litle_request.xmlns = "http://www.litle.com/schema"
495
- # litle_request.id = options['sessionId'] #grab from options; okay if nil
496
- litle_request.numBatchRequests = @num_batch_requests
497
-
498
- xml = litle_request.save_to_xml.to_s
499
- xml[/<\/litleRequest>/]=''
500
- return xml
501
- end
502
-
503
- def get_config(field, options)
504
- if options[field.to_s] == nil and options[field] == nil then
505
- return @config_hash[field.to_s]
506
- elsif options[field.to_s] != nil then
507
- return options[field.to_s]
508
- else
509
- return options[field]
510
- end
511
- end
512
- end
513
- end