qbwc 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -1
  3. data/.travis.yml +6 -0
  4. data/README.md +152 -144
  5. data/Rakefile +7 -1
  6. data/lib/generators/qbwc/install/install_generator.rb +20 -4
  7. data/lib/generators/qbwc/install/templates/config/qbwc.rb +42 -26
  8. data/lib/generators/qbwc/install/templates/controllers/qbwc_controller.rb +2 -38
  9. data/lib/generators/qbwc/install/templates/db/migrate/create_qbwc_jobs.rb +15 -0
  10. data/lib/generators/qbwc/install/templates/db/migrate/create_qbwc_sessions.rb +16 -0
  11. data/lib/qbwc.rb +107 -71
  12. data/lib/qbwc/active_record.rb +6 -0
  13. data/lib/qbwc/active_record/job.rb +111 -0
  14. data/lib/qbwc/active_record/session.rb +52 -0
  15. data/lib/qbwc/controller.rb +176 -0
  16. data/lib/qbwc/job.rb +81 -18
  17. data/lib/qbwc/railtie.rb +8 -0
  18. data/lib/qbwc/request.rb +14 -23
  19. data/lib/qbwc/session.rb +100 -72
  20. data/lib/qbwc/version.rb +1 -1
  21. data/lib/qbwc/worker.rb +16 -0
  22. data/qbwc.gemspec +11 -5
  23. data/test/qbwc/controllers/controller_test.rb +157 -0
  24. data/test/qbwc/integration/job_management_test.rb +86 -0
  25. data/test/qbwc/integration/request_generation_test.rb +340 -0
  26. data/test/qbwc/integration/response_test.rb +303 -0
  27. data/test/qbwc/integration/routes_test.rb +38 -0
  28. data/test/qbwc/integration/session_test.rb +94 -0
  29. data/test/test_helper.rb +248 -0
  30. data/test/wash_out_helper.rb +76 -0
  31. metadata +133 -55
  32. data/Gemfile.lock +0 -72
  33. data/lib/qbwc/soap_wrapper.rb +0 -35
  34. data/lib/qbwc/soap_wrapper/QBWebConnectorSvc.rb +0 -69
  35. data/lib/qbwc/soap_wrapper/QBWebConnectorSvc.wsdl +0 -312
  36. data/lib/qbwc/soap_wrapper/default.rb +0 -198
  37. data/lib/qbwc/soap_wrapper/defaultMappingRegistry.rb +0 -163
  38. data/lib/qbwc/soap_wrapper/defaultServant.rb +0 -133
  39. data/spec/spec_helper.rb +0 -17
@@ -0,0 +1,176 @@
1
+ require 'wash_out/version'
2
+ include WashOut
3
+
4
+ module QBWC
5
+ module Controller
6
+
7
+ AUTHENTICATE_NOT_VALID_USER = 'nvu'
8
+ AUTHENTICATE_NO_WORK = 'none'
9
+
10
+ def self.included(base)
11
+ base.class_eval do
12
+ include WashOut::SOAP
13
+ skip_before_filter :_parse_soap_parameters, :_authenticate_wsse, :_map_soap_parameters, :only => :qwc
14
+ before_filter :get_session, :except => [:qwc, :authenticate, :_generate_wsdl]
15
+ after_filter :save_session, :except => [:qwc, :authenticate, :_generate_wsdl, :close_connection, :connection_error]
16
+
17
+ # wash_out changed the format of app/views/wash_with_soap/rpc/response.builder in commit
18
+ # https://github.com/inossidabile/wash_out/commit/24a77f4a3d874562732c6e8c3a30e8defafea7cb
19
+ wash_out_xml_namespace = (Gem::Version.new(WashOut::VERSION) < Gem::Version.new('0.9.1') ? 'tns:' : '')
20
+
21
+ soap_action 'serverVersion', :to => :server_version,
22
+ :return => {'tns:serverVersionResult' => :string},
23
+ :response_tag => "#{wash_out_xml_namespace}serverVersionResponse"
24
+
25
+ soap_action 'clientVersion', :to => :client_version,
26
+ :args => {:strVersion => :string},
27
+ :return => {'tns:clientVersionResult' => :string},
28
+ :response_tag => "#{wash_out_xml_namespace}clientVersionResponse"
29
+
30
+ soap_action 'authenticate',
31
+ :args => {:strUserName => :string, :strPassword => :string},
32
+ :return => {'tns:authenticateResult' => StringArray},
33
+ :response_tag => "#{wash_out_xml_namespace}authenticateResponse"
34
+
35
+ soap_action 'sendRequestXML', :to => :send_request,
36
+ :args => {:ticket => :string, :strHCPResponse => :string, :strCompanyFilename => :string, :qbXMLCountry => :string, :qbXMLMajorVers => :string, :qbXMLMinorVers => :string},
37
+ :return => {'tns:sendRequestXMLResult' => :string},
38
+ :response_tag => "#{wash_out_xml_namespace}sendRequestXMLResponse"
39
+
40
+ soap_action 'receiveResponseXML', :to => :receive_response,
41
+ :args => {:ticket => :string, :response => :string, :hresult => :string, :message => :string},
42
+ :return => {'tns:receiveResponseXMLResult' => :integer},
43
+ :response_tag => "#{wash_out_xml_namespace}receiveResponseXMLResponse"
44
+
45
+ soap_action 'closeConnection', :to => :close_connection,
46
+ :args => {:ticket => :string},
47
+ :return => {'tns:closeConnectionResult' => :string},
48
+ :response_tag => "#{wash_out_xml_namespace}closeConnectionResponse"
49
+
50
+ soap_action 'connectionError', :to => :connection_error,
51
+ :args => {:ticket => :string, :hresult => :string, :message => :string},
52
+ :return => {'tns:connectionErrorResult' => :string},
53
+ :response_tag => "#{wash_out_xml_namespace}connectionErrorResponse"
54
+
55
+ soap_action 'getLastError', :to => :get_last_error,
56
+ :args => {:ticket => :string},
57
+ :return => {'tns:getLastErrorResult' => :string},
58
+ :response_tag => "#{wash_out_xml_namespace}getLastErrorResponse"
59
+ end
60
+ end
61
+
62
+ def qwc
63
+ # Optional tag
64
+ scheduler_block = ''
65
+ if !QBWC.minutes_to_run.nil?
66
+ scheduler_block = <<SB
67
+ <Scheduler>
68
+ <RunEveryNMinutes>#{QBWC.minutes_to_run}</RunEveryNMinutes>
69
+ </Scheduler>
70
+ SB
71
+ end
72
+
73
+ qwc = <<QWC
74
+ <QBWCXML>
75
+ <AppName>#{Rails.application.class.parent_name} #{Rails.env} #{@app_name_suffix}</AppName>
76
+ <AppID></AppID>
77
+ <AppURL>#{qbwc_action_url(:only_path => false)}</AppURL>
78
+ <AppDescription>Quickbooks integration</AppDescription>
79
+ <AppSupport>#{QBWC.support_site_url || root_url(:protocol => 'https://')}</AppSupport>
80
+ <UserName>#{@username || QBWC.username}</UserName>
81
+ <OwnerID>#{QBWC.owner_id}</OwnerID>
82
+ <FileID>{90A44FB5-33D9-4815-AC85-BC87A7E7D1EB}</FileID>
83
+ <QBType>QBFS</QBType>
84
+ <Style>Document</Style>
85
+ #{scheduler_block}
86
+ </QBWCXML>
87
+ QWC
88
+ send_data qwc, :filename => "#{@filename || Rails.application.class.parent_name}.qwc", :content_type => 'application/x-qwc'
89
+ end
90
+
91
+ class StringArray < WashOut::Type
92
+ map "tns:string" => [:string]
93
+ end
94
+
95
+ def server_version
96
+ render :soap => {"tns:serverVersionResult" => server_version_response}
97
+ end
98
+
99
+ def client_version
100
+ render :soap => {"tns:clientVersionResult" => check_client_version}
101
+ end
102
+
103
+ def authenticate
104
+ username = params[:strUserName]
105
+ password = params[:strPassword]
106
+ if !QBWC.authenticator.nil?
107
+ company_file_path = QBWC.authenticator.call(username, password)
108
+ elsif username == QBWC.username && password == QBWC.password
109
+ company_file_path = QBWC.company_file_path
110
+ else
111
+ company_file_path = nil
112
+ end
113
+
114
+ ticket = nil
115
+ if company_file_path.nil?
116
+ QBWC.logger.info "Authentication of user '#{username}' failed."
117
+ company_file_path = AUTHENTICATE_NOT_VALID_USER
118
+ elsif !QBWC.pending_jobs(company_file_path).present?
119
+ QBWC.logger.info "Authentication of user '#{username}' succeeded, but no jobs pending for '#{company_file_path}'."
120
+ company_file_path = AUTHENTICATE_NO_WORK
121
+ else
122
+ QBWC.logger.info "Authentication of user '#{username}' succeeded, jobs are pending for '#{company_file_path}'."
123
+ ticket = QBWC.storage_module::Session.new(username, company_file_path).ticket
124
+ QBWC.session_initializer.call(get_session(ticket)) unless QBWC.session_initializer.nil?
125
+ end
126
+ render :soap => {"tns:authenticateResult" => {"tns:string" => [ticket || '', company_file_path]}}
127
+ end
128
+
129
+ def send_request
130
+ request = @session.request_to_send
131
+ render :soap => {'tns:sendRequestXMLResult' => request}
132
+ end
133
+
134
+ def receive_response
135
+ if params[:hresult]
136
+ QBWC.logger.warn "#{params[:hresult]}: #{params[:message]}"
137
+ @session.error = params[:message]
138
+ @session.status_code = params[:hresult]
139
+ @session.status_severity = 'Error'
140
+ end
141
+ @session.response = params[:response]
142
+ render :soap => {'tns:receiveResponseXMLResult' => (QBWC::on_error == 'continueOnError' || @session.error.nil?) ? @session.progress : -1}
143
+ end
144
+
145
+ def close_connection
146
+ @session.destroy
147
+ render :soap => {'tns:closeConnectionResult' => 'OK'}
148
+ end
149
+
150
+ def connection_error
151
+ @session.destroy
152
+ logger.warn "#{params[:hresult]}: #{params[:message]}"
153
+ render :soap => {'tns:connectionErrorResult' => 'done'}
154
+ end
155
+
156
+ def get_last_error
157
+ render :soap => {'tns:getLastErrorResult' => @session.error || ''}
158
+ end
159
+
160
+ protected
161
+
162
+ def get_session(ticket = params[:ticket])
163
+ @session = QBWC.storage_module::Session.get(ticket)
164
+ end
165
+
166
+ def save_session
167
+ @session.save if @session
168
+ end
169
+
170
+ def server_version_response
171
+ end
172
+
173
+ def check_client_version
174
+ end
175
+ end
176
+ end
@@ -1,47 +1,110 @@
1
1
  class QBWC::Job
2
2
 
3
- attr_reader :name, :response_proc, :requests
3
+ attr_reader :name, :company, :worker_class
4
4
 
5
- def initialize(name, &block)
5
+ def initialize(name, enabled, company, worker_class, requests = [], data = nil)
6
6
  @name = name
7
- @enabled = true
8
- @requests = block
7
+ @enabled = enabled
8
+ @company = company || QBWC.company_file_path
9
+ @worker_class = worker_class
10
+ @requests = requests
11
+ @data = data
12
+ @request_index = 0
13
+ end
14
+
15
+ def worker
16
+ worker_class.constantize.new
17
+ end
9
18
 
10
- reset
19
+ def process_response(qbxml_response, response, session, advance)
20
+ QBWC.logger.info "Processing response."
21
+ completed_request = requests[request_index]
22
+ advance_next_request if advance
23
+ QBWC.logger.info "Job '#{name}' received response: '#{qbxml_response}'." if QBWC.log_requests_and_responses
24
+ worker.handle_response(response, session, self, completed_request, data)
11
25
  end
12
26
 
13
- def set_response_proc(&block)
14
- @response_proc = block
27
+ def advance_next_request
28
+ new_index = request_index + 1
29
+ QBWC.logger.info "Job '#{name}' advancing to request #'#{new_index}'."
30
+ self.request_index = new_index
15
31
  end
16
32
 
17
33
  def enable
18
- @enabled = true
34
+ self.enabled = true
19
35
  end
20
36
 
21
37
  def disable
22
- @enabled = false
38
+ self.enabled = false
39
+ end
40
+
41
+ def pending?
42
+ if !enabled?
43
+ QBWC.logger.info "Job '#{name}' not enabled."
44
+ return false
45
+ end
46
+ sr = worker.should_run?(self)
47
+ QBWC.logger.info "Job '#{name}' should_run?: #{sr}."
48
+ return sr
23
49
  end
24
50
 
25
51
  def enabled?
26
52
  @enabled
27
53
  end
28
54
 
29
- def next
30
- @request_gen.alive? ? @request_gen.resume : nil
55
+ def requests
56
+ @requests
31
57
  end
32
58
 
33
- def reset
34
- @request_gen = new_request_generator
59
+ def requests=(r)
60
+ @requests = r
35
61
  end
36
62
 
37
- private
63
+ def data
64
+ @data
65
+ end
38
66
 
39
- def new_request_generator
40
- Fiber.new { request_queue.each { |r| Fiber.yield r }; nil }
67
+ def data=(d)
68
+ @data = d
41
69
  end
42
70
 
43
- def request_queue
44
- QBWC::Request.from_array(@requests.call, @response_proc )
71
+ def request_index
72
+ @request_index
73
+ end
74
+
75
+ def request_index=(ri)
76
+ @request_index = ri
77
+ end
78
+
79
+ def requests_provided_when_job_added
80
+ @requests_provided_when_job_added
81
+ end
82
+
83
+ def requests_provided_when_job_added=(value)
84
+ @requests_provided_when_job_added = value
85
+ end
86
+
87
+ def next_request
88
+ # Generate and save the requests to run when starting the job.
89
+ if (requests.nil? || requests.empty?) && ! self.requests_provided_when_job_added
90
+ r = worker.requests(self)
91
+ r = [r] unless r.nil? || r.is_a?(Array)
92
+ self.requests = r
93
+ end
94
+
95
+ QBWC.logger.info("Requests available are '#{requests}'.") if QBWC.log_requests_and_responses
96
+ ri = request_index
97
+ QBWC.logger.info("Request index is '#{ri}'.")
98
+ return nil if ri.nil? || requests.nil? || ri >= requests.length
99
+ nr = requests[ri]
100
+ QBWC.logger.info("Next request is '#{nr}'.") if QBWC.log_requests_and_responses
101
+ return QBWC::Request.new(nr)
102
+ end
103
+ alias :next :next_request # Deprecated method name 'next'
104
+
105
+ def reset
106
+ self.request_index = 0
107
+ self.requests = [] unless self.requests_provided_when_job_added
45
108
  end
46
109
 
47
110
  end
@@ -0,0 +1,8 @@
1
+ require 'wash_out'
2
+
3
+ module QBWC
4
+ class Railtie < ::Rails::Railtie
5
+ config.wash_out.parser = :nokogiri
6
+ config.wash_out.namespace = 'http://developer.intuit.com/'
7
+ end
8
+ end
@@ -1,46 +1,37 @@
1
1
  class QBWC::Request
2
2
 
3
3
  attr_reader :request, :response_proc
4
- attr_accessor :response, :error
5
4
 
6
- def initialize(request, response_proc)
5
+ def initialize(request)
7
6
  #Handle Cases for a request passed in as a Hash or String
8
7
  #If it's a hash verify that it is properly wrapped with qbxml_msg_rq and xml_attributes for on_error events
9
8
  #Allow strings of QBXML to be passed in directly.
10
9
  case
11
10
  when request.is_a?(Hash)
12
-
13
- unless request.keys.include?(:qbxml_msgs_rq)
14
- wrapped_request = { :qbxml_msgs_rq => {:xml_attributes => {"onError"=> QBWC::on_error } } }
15
- wrapped_request[:qbxml_msgs_rq] = wrapped_request[:qbxml_msgs_rq].merge(request)
16
- request = wrapped_request
17
- end
18
-
19
- @request = QBWC.parser.hash_to_qbxml(request)
11
+ request = self.class.wrap_request(request)
12
+ @request = QBWC.parser.to_qbxml(request, {:validate => true})
20
13
  when request.is_a?(String)
21
14
  @request = request
15
+ else
16
+ raise "Request '#{request}' must be a Hash or a String."
22
17
  end
23
- @response_proc = response_proc
24
- end
25
-
26
- def process_response
27
- @response_proc && @response && @response_proc.call(response)
28
18
  end
29
19
 
30
20
  def to_qbxml
31
- QBWC.parser.hash_to_qbxml(request)
21
+ QBWC.parser.to_qbxml(request)
32
22
  end
33
23
 
34
24
  def to_hash
35
- QBWC.parser.qbxml_to_hash @request.to_s
25
+ hash = QBWC.parser.from_qbxml(@request.to_s)["qbxml"]["qbxml_msgs_rq"]
26
+ hash.except('xml_attributes')
36
27
  end
37
28
 
38
- class << self
39
-
40
- def from_array(requests, response_proc)
41
- Array(requests).map { |r| new(r, response_proc) }
42
- end
43
-
29
+ # Wrap a Hash request with qbxml_msgs_rq, if it's not already.
30
+ def self.wrap_request(request)
31
+ return request if request.keys.include?(:qbxml_msgs_rq)
32
+ wrapped_request = { :qbxml_msgs_rq => {:xml_attributes => {"onError"=> QBWC::on_error } } }
33
+ wrapped_request[:qbxml_msgs_rq] = wrapped_request[:qbxml_msgs_rq].merge(request)
34
+ return wrapped_request
44
35
  end
45
36
 
46
37
  end
@@ -1,115 +1,143 @@
1
1
  class QBWC::Session
2
- include Enumerable
3
2
 
4
- attr_reader :current_job, :current_request, :saved_requests, :progress
5
- attr_reader :qbwc_iterator_queue, :qbwc_iterating
3
+ attr_reader :user, :company, :ticket, :progress
4
+ attr_accessor :error, :status_code, :status_severity
6
5
 
7
6
  @@session = nil
8
7
 
9
- def initialize
8
+ def self.get(ticket)
9
+ @@session
10
+ end
11
+
12
+ def initialize(user = nil, company = nil, ticket = nil)
13
+ @user = user
14
+ @company = company
10
15
  @current_job = nil
11
- @current_request = nil
12
- @saved_requests = []
16
+ @error = nil
17
+ @progress = 0
18
+ @iterator_id = nil
19
+ @initial_job_count = pending_jobs.length
13
20
 
14
- @qbwc_iterator_queue = []
15
- @qbwc_iterating = false
21
+ @ticket = ticket || Digest::SHA1.hexdigest("#{Rails.application.config.secret_token}#{Time.now.to_i}")
16
22
 
17
23
  @@session = self
18
- reset
24
+ reset(ticket.nil?)
25
+ end
26
+
27
+ def response_is_error?
28
+ self.error && self.status_severity == 'Error'
19
29
  end
20
30
 
21
- def reset
22
- @progress = QBWC.jobs.blank? ? 100 : 0
23
- enabled_jobs.map { |j| j.reset }
24
- @requests = build_request_generator(enabled_jobs)
31
+ def error_and_stop_requested?
32
+ response_is_error? && QBWC::on_error == 'stopOnError'
25
33
  end
26
34
 
27
35
  def finished?
28
- @progress == 100
36
+ self.progress == 100
37
+ end
38
+
39
+ def next_request
40
+ if current_job.nil? || error_and_stop_requested?
41
+ self.progress = 100
42
+ return nil
43
+ end
44
+ until (request = current_job.next_request) do
45
+ pending_jobs.shift
46
+ reset(true) or break
47
+ end
48
+ jobs_completed = @initial_job_count - pending_jobs.length
49
+ self.progress = ((jobs_completed.to_f / @initial_job_count.to_f ) * 100).to_i
50
+ request
29
51
  end
52
+ alias :next :next_request # Deprecated method name 'next'
53
+
54
+ def current_request
55
+ request = self.next_request
56
+ if request && self.iterator_id.present?
57
+ request = request.to_hash
58
+ request.delete('xml_attributes')
59
+ request.values.first['xml_attributes'] = {'iterator' => 'Continue', 'iteratorID' => self.iterator_id}
60
+ request = QBWC::Request.new(request)
61
+ end
62
+ request
63
+ end
64
+
65
+ def request_to_send
66
+ current_job_name = current_job.name
67
+ request = current_request.try(:request) || ''
68
+ QBWC.logger.info("Sending request from job #{current_job_name}")
69
+ QBWC.logger.info(request) if QBWC.log_requests_and_responses
30
70
 
31
- def next
32
- @requests.alive? ? @requests.resume : nil
71
+ request
33
72
  end
34
73
 
35
74
  def response=(qbxml_response)
36
75
  begin
37
- @current_request.response = QBWC.parser.qbxml_to_hash(qbxml_response)
38
- parse_response_header(@current_request.response)
39
-
40
- if QBWC.delayed_processing
41
- @saved_requests << @current_request
42
- else
43
- @current_request.process_response
76
+ QBWC.logger.info 'Parsing response.'
77
+ unless qbxml_response.nil?
78
+ response = QBWC.parser.from_qbxml(qbxml_response)["qbxml"]["qbxml_msgs_rs"].except("xml_attributes")
79
+ response = response[response.keys.first]
80
+ parse_response_header(response)
44
81
  end
82
+ self.current_job.process_response(qbxml_response, response, self, iterator_id.blank?) unless self.current_job.nil?
83
+ self.next_request # search next request
84
+
45
85
  rescue => e
46
- puts "An error occured in QBWC::Session: #{e}"
47
- puts e
48
- puts e.backtrace
86
+ self.error = e.message
87
+ QBWC.logger.warn "An error occured in QBWC::Session: #{e.message}"
88
+ QBWC.logger.warn e.backtrace.join("\n")
49
89
  end
90
+ end
50
91
 
92
+ def save
51
93
  end
52
94
 
53
- def process_saved_responses
54
- @saved_requests.each { |r| r.process_response }
95
+ def destroy
96
+ self.freeze
97
+ @@session = nil
55
98
  end
56
99
 
57
- private
100
+ protected
58
101
 
59
- def enabled_jobs
60
- QBWC.jobs.values.select { |j| j.enabled? }
61
- end
102
+ attr_accessor :current_job, :iterator_id
103
+ attr_writer :progress
62
104
 
63
- def build_request_generator(jobs)
64
- Fiber.new do
65
- jobs.each do |j|
66
- @current_job = j
67
- while (r = next_request)
68
- @current_request = r
69
- Fiber.yield r
70
- end
71
- end
105
+ private
72
106
 
73
- @progress = 100
74
- nil
75
- end
107
+ def reset(reset_job = false)
108
+ self.current_job = pending_jobs.first
109
+ self.current_job.reset if reset_job && self.current_job
110
+ return self.current_job
76
111
  end
77
112
 
78
- def next_request
79
- (@qbwc_iterating == true && @qbwc_iterator_queue.shift) || @current_job.next
113
+ def pending_jobs
114
+ @pending_jobs ||= QBWC.pending_jobs(@company)
80
115
  end
81
116
 
82
117
  def parse_response_header(response)
83
- return unless response['xml_attributes']
118
+ QBWC.logger.info 'Parsing headers.'
84
119
 
85
- status_code, status_severity, status_message, iterator_remaining_count, iterator_id = \
86
- response['xml_attributes'].values_at('statusCode', 'statusSeverity', 'statusMessage',
87
- 'iteratorRemainingCount', 'iteratorID')
88
-
89
- if status_severity == 'Error' || status_code.to_i > 1 || response.keys.size <= 1
90
- @current_request.error = "QBWC ERROR: #{status_code} - #{status_message}"
91
- else
92
- if iterator_remaining_count.to_i > 0
93
- @qbwc_iterating = true
94
- new_request = @current_request.to_hash
95
- new_request.delete('xml_attributes')
96
- new_request.values.first['xml_attributes'] = {'iterator' => 'Continue', 'iteratorID' => iterator_id}
97
- @qbwc_iterator_queue << QBWC::Request.new(new_request, @current_request.response_proc)
98
- else
99
- @qbwc_iterating = false
100
- end
120
+ self.iterator_id = nil
121
+ self.error = nil
122
+ self.status_code = nil
123
+ self.status_severity = nil
124
+
125
+ if response.is_a? Array
126
+ response = response.find {|r| r.is_a?(Hash) && r['xml_attributes'] && r['xml_attributes']['statusCode'].to_i > 1} || response.first
101
127
  end
102
- end
128
+ return unless response.is_a?(Hash) && response['xml_attributes']
103
129
 
104
- class << self
130
+ @status_code, @status_severity, status_message, iterator_remaining_count, iterator_id = \
131
+ response['xml_attributes'].values_at('statusCode', 'statusSeverity', 'statusMessage',
132
+ 'iteratorRemainingCount', 'iteratorID')
133
+ QBWC.logger.info "Parsed headers. statusSeverity: '#{status_severity}'. statusCode: '#{@status_code}'"
105
134
 
106
- def new_or_unfinished
107
- (!@@session || @@session.finished?) ? new : @@session
108
- end
135
+ if @status_severity == 'Error' || @status_severity == 'Warn'
136
+ self.error = "QBWC #{@status_severity.upcase}: #{@status_code} - #{status_message}"
137
+ @status_severity == 'Error' ? QBWC.logger.error(self.error) : QBWC.logger.warn(self.error)
138
+ end
109
139
 
110
- end
140
+ self.iterator_id = iterator_id if iterator_remaining_count.to_i > 0 && @status_severity != 'Error'
111
141
 
112
- def self.session
113
- @@session
114
- end
142
+ end
115
143
  end