LitleOnline 8.18.0 → 8.19.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.
- checksums.yaml +15 -0
- data/CHANGELOG +5 -1
- data/CHANGELOG~ +81 -0
- data/Rakefile +2 -2
- data/Rakefile~ +93 -0
- data/lib/LitleOnlineRequest.rb +2 -2
- data/lib/LitleOnlineRequest.rb~ +198 -0
- data/lib/LitleRequest.rb +3 -3
- data/lib/LitleRequest.rb~ +513 -0
- data/lib/LitleTransaction.rb +6 -4
- data/lib/LitleTransaction.rb~ +297 -0
- data/lib/XMLFields.rb +15 -3
- data/lib/XMLFields.rb~ +1380 -0
- data/test/functional/ts_all.rb~ +44 -0
- data/test/unit/test_LitleOnlineRequest.rb +3 -3
- data/test/unit/test_LitleOnlineRequest.rb~ +296 -0
- data/test/unit/test_sale.rb +3 -3
- data/test/unit/test_sale.rb~ +390 -0
- data/test/unit/test_xmlfields.rb +20 -0
- data/test/unit/test_xmlfields.rb~ +2515 -0
- metadata +107 -81
@@ -0,0 +1,513 @@
|
|
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
|