zuora_api 1.7.81 → 1.8.00
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 +4 -4
- data/.gitignore +10 -0
- data/.gitlab-ci.yml +63 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +105 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +117 -0
- data/README.md +0 -10
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/zuora_api/exceptions.rb +3 -17
- data/lib/zuora_api/login.rb +257 -324
- data/lib/zuora_api/logins/basic.rb +101 -10
- data/lib/zuora_api/logins/oauth.rb +84 -24
- data/lib/zuora_api/version.rb +1 -1
- data/zuora_api.gemspec +30 -0
- metadata +20 -25
- data/MIT-LICENSE +0 -20
data/lib/zuora_api/login.rb
CHANGED
|
@@ -7,7 +7,7 @@ module ZuoraAPI
|
|
|
7
7
|
class Login
|
|
8
8
|
ENVIRONMENTS = [TEST = 'Test', SANDBOX = 'Sandbox', PRODUCTION = 'Production', PREFORMANCE = 'Preformance', SERVICES = 'Services', UNKNOWN = 'Unknown', STAGING = 'Staging' ]
|
|
9
9
|
REGIONS = [EU = 'EU', US = 'US', NA = 'NA' ]
|
|
10
|
-
|
|
10
|
+
MIN_Endpoint = '96.0'
|
|
11
11
|
XML_SAVE_OPTIONS = Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
|
12
12
|
|
|
13
13
|
CONNECTION_EXCEPTIONS = [
|
|
@@ -21,7 +21,7 @@ module ZuoraAPI
|
|
|
21
21
|
].freeze
|
|
22
22
|
|
|
23
23
|
CONNECTION_READ_EXCEPTIONS = [
|
|
24
|
-
|
|
24
|
+
Net::ReadTimeout,
|
|
25
25
|
Errno::ECONNRESET,
|
|
26
26
|
Errno::EPIPE
|
|
27
27
|
].freeze
|
|
@@ -39,8 +39,8 @@ module ZuoraAPI
|
|
|
39
39
|
|
|
40
40
|
ZUORA_SERVER_ERRORS = [
|
|
41
41
|
ZuoraAPI::Exceptions::ZuoraAPIInternalServerError,
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout,
|
|
43
|
+
ZuoraAPI::Exceptions::ZuoraAPIReadTimeout,
|
|
44
44
|
ZuoraAPI::Exceptions::ZuoraUnexpectedError
|
|
45
45
|
].freeze
|
|
46
46
|
|
|
@@ -50,12 +50,10 @@ module ZuoraAPI
|
|
|
50
50
|
raise "URL is nil or empty, but URL is required" if url.nil? || url.empty?
|
|
51
51
|
# raise "URL is improper. URL must contain zuora.com, zuora.eu, or zuora.na" if /zuora.com|zuora.eu|zuora.na/ === url
|
|
52
52
|
self.hostname = /(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url)[0] if !/(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url).nil?
|
|
53
|
-
self.update_environment
|
|
54
|
-
min_endpoint = MIN_Endpoints[self.environment.to_sym]
|
|
55
53
|
if !/apps\/services\/a\/\d+\.\d$/.match(url.strip)
|
|
56
|
-
self.url = "https://#{hostname}/apps/services/a/#{
|
|
57
|
-
elsif
|
|
58
|
-
self.url = url.gsub(/(\d+\.\d)$/,
|
|
54
|
+
self.url = "https://#{hostname}/apps/services/a/#{MIN_Endpoint}"
|
|
55
|
+
elsif MIN_Endpoint.to_f > url.scan(/(\d+\.\d)$/).dig(0,0).to_f
|
|
56
|
+
self.url = url.gsub(/(\d+\.\d)$/, MIN_Endpoint)
|
|
59
57
|
else
|
|
60
58
|
self.url = url
|
|
61
59
|
end
|
|
@@ -67,6 +65,7 @@ module ZuoraAPI
|
|
|
67
65
|
self.status = status.blank? ? "Active" : status
|
|
68
66
|
self.user_info = Hash.new
|
|
69
67
|
self.update_region
|
|
68
|
+
self.update_environment
|
|
70
69
|
self.update_zconnect_provider
|
|
71
70
|
@timeout_sleep = 5
|
|
72
71
|
end
|
|
@@ -156,7 +155,7 @@ module ZuoraAPI
|
|
|
156
155
|
# 1. Pass in cookies and optionally custom_authorities, name, and description
|
|
157
156
|
# 2. Pass in user_id, entity_ids, client_id, client_secret, and optionally custom_authorities, name, and description
|
|
158
157
|
# https://intranet.zuora.com/confluence/display/Sunburst/Create+an+OAuth+Client+through+API+Gateway#CreateanOAuthClientthroughAPIGateway-ZSession
|
|
159
|
-
def get_oauth_client (custom_authorities = [], info_name: "No Name", info_desc: "This client was created without a description.", user_id: nil, entity_ids: nil, client_id: nil, client_secret: nil, new_client_id: nil, new_client_secret: nil, cookies: nil, chomp_v1_from_genesis_endpoint: false
|
|
158
|
+
def get_oauth_client (custom_authorities = [], info_name: "No Name", info_desc: "This client was created without a description.", user_id: nil, entity_ids: nil, client_id: nil, client_secret: nil, new_client_id: nil, new_client_secret: nil, cookies: nil, chomp_v1_from_genesis_endpoint: false)
|
|
160
159
|
authorization = ""
|
|
161
160
|
new_client_id = SecureRandom.uuid if new_client_id.blank?
|
|
162
161
|
new_client_secret = SecureRandom.hex(10) if new_client_secret.blank?
|
|
@@ -186,7 +185,7 @@ module ZuoraAPI
|
|
|
186
185
|
oauth_response = HTTParty.post(endpoint, :headers => {'authorization' => authorization, 'Content-Type' => 'application/json'}, :body => {'clientId' => new_client_id, 'clientSecret' => new_client_secret, 'userId' => user_id, 'entityIds' => entity_ids, 'customAuthorities' => custom_authorities, 'additionalInformation' => {'description' => info_desc, 'name' => info_name}}.to_json)
|
|
187
186
|
output_json = JSON.parse(oauth_response.body)
|
|
188
187
|
if oauth_response.code == 201
|
|
189
|
-
output_json["clientSecret"] = new_client_secret
|
|
188
|
+
output_json["clientSecret"] = new_client_secret
|
|
190
189
|
return output_json
|
|
191
190
|
elsif oauth_response.code == 401 && !oauth_response.message.blank?
|
|
192
191
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["message"], oauth_response)
|
|
@@ -253,7 +252,7 @@ module ZuoraAPI
|
|
|
253
252
|
end
|
|
254
253
|
|
|
255
254
|
def update_environment
|
|
256
|
-
if !self.
|
|
255
|
+
if !self.url.blank?
|
|
257
256
|
case self.hostname
|
|
258
257
|
when /(?<=\.|\/|-|^)(apisandbox|sandbox)(?=\.|\/|-|$)/
|
|
259
258
|
self.environment = 'Sandbox'
|
|
@@ -276,13 +275,13 @@ module ZuoraAPI
|
|
|
276
275
|
end
|
|
277
276
|
|
|
278
277
|
def update_zconnect_provider
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
region = update_region
|
|
279
|
+
environment = update_environment
|
|
281
280
|
mappings = {"US" => {"Sandbox" => "ZConnectSbx", "Services" => "ZConnectSvcUS", "Production" => "ZConnectProd", "Performance" => "ZConnectPT1", "Test" => "ZConnectTest", "Staging" => "ZConnectQA", "KubeSTG" => "ZConnectDev", "KubeDEV" => "ZConnectDev", "KubePROD" => "ZConnectDev"},
|
|
282
281
|
"NA" => {"Sandbox" => "ZConnectSbxNA", "Services" => "ZConnectSvcNA", "Production" => "ZConnectProdNA", "Performance" => "ZConnectPT1NA"},
|
|
283
282
|
"EU" => {"Sandbox" => "ZConnectSbxEU", "Services" => "ZConnectSvcEU", "Production" => "ZConnectProdEU", "Performance" => "ZConnectPT1EU", "Test" => "ZConnectTest"},
|
|
284
283
|
"Unknown" => {"Unknown" => "Unknown"}}
|
|
285
|
-
self.zconnect_provider = mappings[
|
|
284
|
+
self.zconnect_provider = mappings[region][environment]
|
|
286
285
|
end
|
|
287
286
|
|
|
288
287
|
def aqua_endpoint(url="")
|
|
@@ -322,8 +321,8 @@ module ZuoraAPI
|
|
|
322
321
|
return domain ? endpoint.concat(prefix).concat(url) : prefix.concat(url)
|
|
323
322
|
end
|
|
324
323
|
|
|
325
|
-
def rest_domain
|
|
326
|
-
return URI(
|
|
324
|
+
def rest_domain
|
|
325
|
+
return URI(self.rest_endpoint).host
|
|
327
326
|
end
|
|
328
327
|
|
|
329
328
|
def fileURL(url="")
|
|
@@ -335,41 +334,10 @@ module ZuoraAPI
|
|
|
335
334
|
end
|
|
336
335
|
|
|
337
336
|
def new_session(auth_type: :basic, debug: false, zuora_track_id: nil)
|
|
338
|
-
retries ||= 2
|
|
339
|
-
yield
|
|
340
|
-
|
|
341
|
-
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
|
342
|
-
self.status = 'Invalid'
|
|
343
|
-
self.current_error = ex.message
|
|
344
|
-
raise
|
|
345
|
-
rescue ZuoraAPI::Exceptions::ZuoraAPIError => ex
|
|
346
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(ex.message, ex.response)
|
|
347
|
-
|
|
348
|
-
rescue ZuoraAPI::Exceptions::ZuoraAPIInternalServerError => ex
|
|
349
|
-
raise ex if retries.zero?
|
|
350
|
-
|
|
351
|
-
retries -= 1
|
|
352
|
-
sleep(self.timeout_sleep)
|
|
353
|
-
retry
|
|
354
|
-
|
|
355
|
-
rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
|
|
356
|
-
self.log(location: "BasicLogin", exception: ex, message: "Timed out", level: :error)
|
|
357
|
-
|
|
358
|
-
self.current_error = "Request timed out. Try again"
|
|
359
|
-
self.status = 'Timeout'
|
|
360
|
-
|
|
361
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
|
|
362
|
-
|
|
363
|
-
rescue EOFError
|
|
364
|
-
if self.url.match?(/.*services\d{1,}.zuora.com*/)
|
|
365
|
-
self.current_error = "Services tenant '#{self.url.scan(/.*\/\/(services\d{1,}).zuora.com*/).last.first}' is no longer available."
|
|
366
|
-
self.status = 'Not Available'
|
|
367
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
|
|
368
|
-
end
|
|
369
|
-
|
|
370
337
|
end
|
|
371
338
|
|
|
372
339
|
def get_session(prefix: false, auth_type: :basic, zuora_track_id: nil)
|
|
340
|
+
Rails.logger.debug("Get session for #{auth_type} - #{self.class.to_s}") if Rails.env.to_s == 'development'
|
|
373
341
|
case auth_type
|
|
374
342
|
when :basic
|
|
375
343
|
if self.current_session.blank?
|
|
@@ -378,13 +346,14 @@ module ZuoraAPI
|
|
|
378
346
|
if self.bearer_token.blank? || self.oauth_expired?
|
|
379
347
|
self.new_session(auth_type: :bearer, zuora_track_id: zuora_track_id)
|
|
380
348
|
end
|
|
381
|
-
self.get_z_session(zuora_track_id: zuora_track_id)
|
|
349
|
+
self.get_z_session(zuora_track_id: zuora_track_id) if self.status == 'Active'
|
|
382
350
|
when 'ZuoraAPI::Basic'
|
|
383
351
|
self.new_session(auth_type: :basic, zuora_track_id: zuora_track_id)
|
|
384
352
|
else
|
|
385
353
|
self.new_session(auth_type: :basic, zuora_track_id: zuora_track_id)
|
|
386
354
|
end
|
|
387
355
|
end
|
|
356
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error) if self.status != 'Active'
|
|
388
357
|
return prefix ? "ZSession #{self.current_session}" : self.current_session.to_s
|
|
389
358
|
when :bearer
|
|
390
359
|
case self.class.to_s
|
|
@@ -397,6 +366,8 @@ module ZuoraAPI
|
|
|
397
366
|
else
|
|
398
367
|
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Unknown Login, does not support Authentication of Type: #{auth_type}")
|
|
399
368
|
end
|
|
369
|
+
|
|
370
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error) if self.status != 'Active'
|
|
400
371
|
return prefix ? "Bearer #{self.bearer_token}" : self.bearer_token.to_s
|
|
401
372
|
end
|
|
402
373
|
end
|
|
@@ -404,18 +375,16 @@ module ZuoraAPI
|
|
|
404
375
|
def soap_call(
|
|
405
376
|
ns1: 'ns1',
|
|
406
377
|
ns2: 'ns2',
|
|
407
|
-
batch_size: nil,
|
|
408
|
-
headers: {},
|
|
378
|
+
batch_size: nil,
|
|
409
379
|
single_transaction: false,
|
|
410
380
|
debug: false,
|
|
411
381
|
zuora_track_id: nil,
|
|
412
382
|
errors: [ZuoraAPI::Exceptions::ZuoraAPISessionError].concat(ZUORA_API_ERRORS),
|
|
413
383
|
z_session: true,
|
|
414
384
|
timeout_retry: false,
|
|
415
|
-
timeout:
|
|
385
|
+
timeout: 120,
|
|
416
386
|
timeout_sleep_interval: self.timeout_sleep,
|
|
417
387
|
output_exception_messages: true,
|
|
418
|
-
skip_session: false,
|
|
419
388
|
**keyword_args)
|
|
420
389
|
tries ||= 2
|
|
421
390
|
xml = Nokogiri::XML::Builder.new do |xml|
|
|
@@ -425,10 +394,8 @@ module ZuoraAPI
|
|
|
425
394
|
'xmlns:api' => "http://api.zuora.com/",
|
|
426
395
|
"xmlns:#{ns1}" => "http://api.zuora.com/") do
|
|
427
396
|
xml['SOAP-ENV'].Header do
|
|
428
|
-
|
|
429
|
-
xml["#{ns1}"].
|
|
430
|
-
xml["#{ns1}"].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: zuora_track_id)
|
|
431
|
-
end
|
|
397
|
+
xml["#{ns1}"].SessionHeader do
|
|
398
|
+
xml["#{ns1}"].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: zuora_track_id)
|
|
432
399
|
end
|
|
433
400
|
if single_transaction
|
|
434
401
|
xml["#{ns1}"].CallOptions do
|
|
@@ -446,11 +413,12 @@ module ZuoraAPI
|
|
|
446
413
|
end
|
|
447
414
|
end
|
|
448
415
|
end
|
|
416
|
+
|
|
449
417
|
input_xml = Nokogiri::XML(xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip)
|
|
450
418
|
input_xml.xpath('//ns1:session', 'ns1' =>'http://api.zuora.com/').children.remove
|
|
451
419
|
Rails.logger.debug("Request SOAP XML: #{input_xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip}") if debug
|
|
452
420
|
|
|
453
|
-
headers
|
|
421
|
+
headers = { 'Content-Type' => "text/xml; charset=utf-8", 'Accept' => 'text/xml'}
|
|
454
422
|
headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
|
|
455
423
|
|
|
456
424
|
request = HTTParty::Request.new(
|
|
@@ -467,11 +435,7 @@ module ZuoraAPI
|
|
|
467
435
|
Rails.logger.debug("Response SOAP XML: #{output_xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip}") if debug
|
|
468
436
|
|
|
469
437
|
raise_errors(type: :SOAP, body: output_xml, response: response)
|
|
470
|
-
|
|
471
|
-
return output_xml, input_xml, response
|
|
472
|
-
|
|
473
438
|
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
|
474
|
-
raise if skip_session
|
|
475
439
|
if !tries.zero? && z_session
|
|
476
440
|
tries -= 1
|
|
477
441
|
Rails.logger.debug("SOAP Call - Session Invalid")
|
|
@@ -483,33 +447,39 @@ module ZuoraAPI
|
|
|
483
447
|
end
|
|
484
448
|
|
|
485
449
|
retry
|
|
450
|
+
else
|
|
451
|
+
if errors.include?(ex.class)
|
|
452
|
+
raise ex
|
|
453
|
+
else
|
|
454
|
+
return output_xml, input_xml, response
|
|
455
|
+
end
|
|
486
456
|
end
|
|
487
|
-
|
|
488
|
-
raise ex if errors.include?(ex.class)
|
|
489
|
-
|
|
490
|
-
return output_xml, input_xml, response
|
|
491
|
-
|
|
492
457
|
rescue *ZUORA_API_ERRORS => ex
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
458
|
+
if errors.include?(ex.class)
|
|
459
|
+
raise ex
|
|
460
|
+
else
|
|
461
|
+
response = ex.response unless response
|
|
462
|
+
return output_xml, input_xml, response
|
|
463
|
+
end
|
|
498
464
|
rescue *CONNECTION_EXCEPTIONS => ex
|
|
499
|
-
if
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
465
|
+
if tries.zero?
|
|
466
|
+
if output_exception_messages
|
|
467
|
+
if Rails.logger.class.to_s == "Ougai::Logger"
|
|
468
|
+
Rails.logger.error("SOAP Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
|
|
469
|
+
else
|
|
470
|
+
Rails.logger.error("SOAP Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
raise ex
|
|
504
474
|
end
|
|
505
475
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
476
|
+
tries -= 1
|
|
477
|
+
sleep(timeout_sleep_interval)
|
|
478
|
+
retry
|
|
509
479
|
rescue *CONNECTION_READ_EXCEPTIONS => ex
|
|
510
480
|
if !tries.zero?
|
|
511
481
|
tries -= 1
|
|
512
|
-
|
|
482
|
+
|
|
513
483
|
if ex.is_a?(Errno::ECONNRESET) && ex.message.include?('SSL_connect')
|
|
514
484
|
retry
|
|
515
485
|
elsif timeout_retry
|
|
@@ -518,74 +488,19 @@ module ZuoraAPI
|
|
|
518
488
|
end
|
|
519
489
|
end
|
|
520
490
|
|
|
521
|
-
|
|
522
|
-
|
|
491
|
+
if output_exception_messages
|
|
492
|
+
if Rails.logger.class.to_s == "Ougai::Logger"
|
|
493
|
+
Rails.logger.error("SOAP Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
|
|
494
|
+
else
|
|
495
|
+
Rails.logger.error("SOAP Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received read timeout from #{url}", nil, request) if ex.instance_of?(Net::ReadTimeout)
|
|
523
499
|
raise ex
|
|
524
|
-
|
|
525
500
|
rescue => ex
|
|
526
501
|
raise ex
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
def error_logger(ex)
|
|
532
|
-
exception_args = Rails.logger.with_fields.merge(self.exception_args(ex))
|
|
533
|
-
case ex
|
|
534
|
-
when ZuoraAPI::Exceptions::ZuoraAPIUnkownError, ZuoraAPI::Exceptions::ZuoraDataIntegrity
|
|
535
|
-
Rails.logger.error('Zuora Unknown/Integrity Error', ex, exception_args)
|
|
536
|
-
when ZuoraAPI::Exceptions::ZuoraAPIRequestLimit
|
|
537
|
-
Rails.logger.info('Zuora APILimit Reached', ex, exception_args)
|
|
538
|
-
when *(ZuoraAPI::Login::ZUORA_API_ERRORS-ZuoraAPI::Login::ZUORA_SERVER_ERRORS)
|
|
539
|
-
#Rails.logger.debug('Zuora API Error', ex, self.exception_args(ex))
|
|
540
|
-
when *ZuoraAPI::Login::ZUORA_SERVER_ERRORS
|
|
541
|
-
Rails.logger.error('Zuora Server Error', ex, exception_args)
|
|
542
|
-
end
|
|
543
|
-
end
|
|
544
|
-
|
|
545
|
-
def log(location: "Rest Call", exception: nil, message: "Timed out will retry after #{self.timeout_sleep} seconds", level: :info )
|
|
546
|
-
level = :debug if ![:debug, :info, :warn, :error, :fatal].include?(level)
|
|
547
|
-
if Rails.logger.class.to_s == "Ougai::Logger"
|
|
548
|
-
Rails.logger.send(level.to_sym, "#{location} - #{message}", exception)
|
|
549
|
-
else
|
|
550
|
-
Rails.logger.send(level.to_sym, "#{location} - #{exception.class} #{message}")
|
|
551
|
-
end
|
|
552
|
-
end
|
|
553
|
-
|
|
554
|
-
def exception_args(ex)
|
|
555
|
-
args = {}
|
|
556
|
-
if defined?(ex.response) && ex.response.present?
|
|
557
|
-
args.merge!({
|
|
558
|
-
request: {
|
|
559
|
-
path: ex.response.request.path.to_s,
|
|
560
|
-
method: ex.response.request.http_method.to_s.split("Net::HTTP::").last.upcase,
|
|
561
|
-
params: ex.response.request.raw_body.to_s,
|
|
562
|
-
headers: ex.response.request.options[:headers].map{|k,v| [k.to_s, k.to_s.downcase.strip == "authorization" ? "VALUE FILTERED" : v]}.to_h.to_s,
|
|
563
|
-
},
|
|
564
|
-
response: {
|
|
565
|
-
status: ex.response.code,
|
|
566
|
-
params: ex.response.body.to_s,
|
|
567
|
-
headers: ex.response.headers.to_s,
|
|
568
|
-
},
|
|
569
|
-
zuora_trace_id: ex.response.headers["zuora-request-id"],
|
|
570
|
-
zuora_track_id: ex.response.request.options[:headers]["Zuora-Track-Id"],
|
|
571
|
-
})
|
|
572
|
-
elsif defined?(ex.request) && ex.request.present?
|
|
573
|
-
args.merge!({
|
|
574
|
-
request: {
|
|
575
|
-
path: ex.request.path.to_s,
|
|
576
|
-
method: ex.request.http_method.to_s.split("Net::HTTP::").last.upcase,
|
|
577
|
-
params: ex.request.options[:body],
|
|
578
|
-
headers: ex.request.options[:headers].map{|k,v| [k.to_s, k.to_s.downcase.strip == "authorization" ? "VALUE FILTERED" : v]}.to_h.to_s
|
|
579
|
-
}
|
|
580
|
-
})
|
|
581
|
-
args.merge!({
|
|
582
|
-
zuora_track_id: ex.request.options[:headers]["Zuora-Track-Id"]
|
|
583
|
-
}) if ex.request.options[:headers]["Zuora-Track-Id"].present?
|
|
584
|
-
end
|
|
585
|
-
rescue => ex
|
|
586
|
-
Rails.logger.error("Failed to create exception arguments", ex, args)
|
|
587
|
-
ensure
|
|
588
|
-
return args
|
|
502
|
+
else
|
|
503
|
+
return output_xml, input_xml, response
|
|
589
504
|
end
|
|
590
505
|
|
|
591
506
|
def raise_errors(type: :SOAP, body: nil, response: nil)
|
|
@@ -602,13 +517,13 @@ module ZuoraAPI
|
|
|
602
517
|
end
|
|
603
518
|
|
|
604
519
|
if [502,503].include?(response.code)
|
|
605
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout.new("Received #{response.code} from
|
|
520
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout.new("Received #{response.code} from #{request_uri}", response)
|
|
606
521
|
end
|
|
607
522
|
|
|
608
523
|
# Check failure response code
|
|
609
524
|
case response.code
|
|
610
525
|
when 504
|
|
611
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received 504 from
|
|
526
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received 504 from #{request_uri}", response)
|
|
612
527
|
when 429
|
|
613
528
|
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("The total number of concurrent requests has exceeded the limit allowed by the system. Please resubmit your request later.", response)
|
|
614
529
|
when 401
|
|
@@ -629,10 +544,6 @@ module ZuoraAPI
|
|
|
629
544
|
when :SOAP
|
|
630
545
|
error, success, message = get_soap_error_and_message(body)
|
|
631
546
|
|
|
632
|
-
if body.xpath('//fns:LoginFault', 'fns' =>'http://fault.api.zuora.com/').present?
|
|
633
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(message, response)
|
|
634
|
-
end
|
|
635
|
-
|
|
636
547
|
if body.xpath('//ns1:queryResponse', 'ns1' => 'http://api.zuora.com/').present? &&
|
|
637
548
|
body.xpath(
|
|
638
549
|
'//ns1:records[@xsi:type="ns2:Export"]',
|
|
@@ -640,12 +551,12 @@ module ZuoraAPI
|
|
|
640
551
|
).present?
|
|
641
552
|
result = body.xpath('//ns2:Status', 'ns2' => 'http://object.api.zuora.com/').text
|
|
642
553
|
if result == 'Failed'
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
error, message = ['UNEXPECTED_ERROR', new_message] if new_message.present?
|
|
554
|
+
reason = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
|
|
555
|
+
if reason.present?
|
|
556
|
+
message = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
|
|
557
|
+
error = message.match(/^[\w\d]{16}\: (Unexpected error.|No HTTP Response|Socket Timeout|There is an internal error, please try again later)/).present? ? 'UNEXPECTED_ERROR' : 'FATAL_ERROR'
|
|
648
558
|
else
|
|
559
|
+
error = 'FATAL_ERROR'
|
|
649
560
|
message = 'Export failed due to unknown reason. Consult api logs.'
|
|
650
561
|
end
|
|
651
562
|
end
|
|
@@ -694,31 +605,14 @@ module ZuoraAPI
|
|
|
694
605
|
when /^GET::400::\/api\/rest\/v1\/reports\/(reportlabels\/)?([a-zA-Z0-9\-_]+)\/report-details$/ # Get report, capture of the id is present if needed in future error responses.
|
|
695
606
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(reporting_message, response) if reporting_message.present?
|
|
696
607
|
end
|
|
697
|
-
when /\/objects\/batch\//
|
|
698
|
-
if body['code'].present? && /61$/.match(body['code'].to_s).present? # if last 2 digits of code are 61
|
|
699
|
-
raise ZuoraAPI::Exceptions::ZuoraAPITemporaryError.new(body['message'], nil, body['details'])
|
|
700
|
-
end
|
|
701
|
-
when /^\/api\/v1\/payment_plans.*/
|
|
702
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(body['error'], response) if body['error']
|
|
703
608
|
end
|
|
704
609
|
|
|
705
610
|
body = body.dig("results").present? ? body["results"] : body if body.class == Hash
|
|
706
611
|
if body.class == Hash && (!body["success"] || !body["Success"] || response.code != 200)
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
message_keys.each do |msg_key|
|
|
712
|
-
messages_array = body.fetch(rsn_key, []).map {|error| error[msg_key]}.compact
|
|
713
|
-
break if messages_array.present?
|
|
714
|
-
end
|
|
715
|
-
codes_array = body.fetch(rsn_key, []).map {|error| error['code']}.compact
|
|
716
|
-
break if messages_array.present? && codes_array.present?
|
|
717
|
-
end
|
|
718
|
-
if body.dig('error').class == Hash
|
|
719
|
-
messages_array = messages_array.push(body.dig("error", 'message')).compact
|
|
720
|
-
codes_array = codes_array.push(body.dig("error", 'code')).compact
|
|
721
|
-
end
|
|
612
|
+
messages_array = body.fetch("reasons", []).map {|error| error['message']}.compact
|
|
613
|
+
messages_array = messages_array.push(body.dig("error", 'message')).compact if body.dig('error').class == Hash
|
|
614
|
+
codes_array = body.fetch("reasons", []).map {|error| error['code']}.compact
|
|
615
|
+
codes_array = codes_array.push(body.dig("error", 'code')).compact if body.dig('error').class == Hash
|
|
722
616
|
|
|
723
617
|
if body['message'] == 'request exceeded limit'
|
|
724
618
|
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("The total number of concurrent requests has exceeded the limit allowed by the system. Please resubmit your request later.", response)
|
|
@@ -750,11 +644,7 @@ module ZuoraAPI
|
|
|
750
644
|
end
|
|
751
645
|
|
|
752
646
|
if body['error'] == 'Unauthorized' && body['status'] == 401
|
|
753
|
-
|
|
754
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(body['message'], response)
|
|
755
|
-
else
|
|
756
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}", response)
|
|
757
|
-
end
|
|
647
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}", response)
|
|
758
648
|
end
|
|
759
649
|
#Authentication failed
|
|
760
650
|
if (codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(11) || response.code == 401) && !codes_array.include?(422)
|
|
@@ -861,7 +751,7 @@ module ZuoraAPI
|
|
|
861
751
|
output_json = JSON.parse(response.body)
|
|
862
752
|
self.raise_errors(type: :JSON, body: output_json, response: response)
|
|
863
753
|
|
|
864
|
-
elsif (response_content_types.include?('application/xml') || response_content_types.include?('text/xml')
|
|
754
|
+
elsif (response_content_types.include?('application/xml') || response_content_types.include?('text/xml')) and type != :xml
|
|
865
755
|
output_xml = Nokogiri::XML(response.body)
|
|
866
756
|
self.raise_errors(type: :SOAP, body: output_xml, response: response)
|
|
867
757
|
|
|
@@ -881,8 +771,6 @@ module ZuoraAPI
|
|
|
881
771
|
raise ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout.new(error_message, response)
|
|
882
772
|
when /Client sent a bad request./, /Bad Request/, /403 Forbidden/
|
|
883
773
|
raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(error_message, response)
|
|
884
|
-
when /414 Request-URI Too Large/
|
|
885
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Request URL is too long", response)
|
|
886
774
|
else
|
|
887
775
|
raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(error_message, response)
|
|
888
776
|
end
|
|
@@ -909,11 +797,6 @@ module ZuoraAPI
|
|
|
909
797
|
message = body.xpath('//ns1:Message', 'ns1' =>'http://api.zuora.com/').text
|
|
910
798
|
end
|
|
911
799
|
|
|
912
|
-
if error.blank? || message.blank?
|
|
913
|
-
error = body.xpath('//soapenv:Value', 'soapenv'=>'http://www.w3.org/2003/05/soap-envelope').text
|
|
914
|
-
message = body.xpath('//soapenv:Text', 'soapenv'=>'http://www.w3.org/2003/05/soap-envelope').text
|
|
915
|
-
end
|
|
916
|
-
|
|
917
800
|
#Update/Create/Delete Calls with multiple requests and responses
|
|
918
801
|
if body.xpath('//ns1:result', 'ns1' =>'http://api.zuora.com/').size > 0 && body.xpath('//ns1:Errors', 'ns1' =>'http://api.zuora.com/').size > 0
|
|
919
802
|
error = []
|
|
@@ -957,22 +840,17 @@ module ZuoraAPI
|
|
|
957
840
|
raise ZuoraAPI::Exceptions::ZuoraAPIUnkownError.new(message, response, errors, success)
|
|
958
841
|
end
|
|
959
842
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
|
|
960
|
-
when
|
|
843
|
+
when /invalid/, /^DUPLICATE_VALUE/, /^REQUEST_REJECTED/, /INVALID_ID/, /MAX_RECORDS_EXCEEDED/, /INVALID_FIELD/, /MALFORMED_QUERY/, /NO_PERMISSION/, /PDF_QUERY_ERROR/, /MISSING_REQUIRED_VALUE/, /INVALID_TYPE/, /TRANSACTION_FAILED/, /API_DISABLED/, /CANNOT_DELETE/, /ACCOUNTING_PERIOD_CLOSED/
|
|
961
844
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
|
|
962
845
|
when /.*UNEXPECTED_ERROR/
|
|
963
846
|
raise ZuoraAPI::Exceptions::ZuoraUnexpectedError.new(message, response, errors, success)
|
|
964
847
|
when /.*soapenv:Server.*/
|
|
965
848
|
if /^Invalid value.*for type.*|^Id is invalid|^date string can not be less than 19 charactors$/.match(message).present?
|
|
966
849
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
|
|
967
|
-
elsif /^
|
|
850
|
+
elsif /^Invalid white space character \(.*\) in text to output$|^Invalid null character in text to output$/.match(message).present?
|
|
968
851
|
raise ZuoraAPI::Exceptions::ZuoraAPIUnkownError.new(message, response, errors, success)
|
|
969
852
|
end
|
|
970
853
|
raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(message, response, errors, success)
|
|
971
|
-
when /soapenv:Receiver/
|
|
972
|
-
if /^com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character.*$/.match(message).present?
|
|
973
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
|
|
974
|
-
end
|
|
975
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(message, response, errors, success)
|
|
976
854
|
else
|
|
977
855
|
raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new("Z:#{error}::#{message}", response, errors, success)
|
|
978
856
|
end
|
|
@@ -1022,7 +900,7 @@ module ZuoraAPI
|
|
|
1022
900
|
base = self.url.include?(".com") ? self.url.split(".com")[0].concat(".com") : self.url.split(".eu")[0].concat(".eu")
|
|
1023
901
|
url = object ? "#{base}/apps/api/describe/#{object}" : "#{base}/apps/api/describe/"
|
|
1024
902
|
headers = self.entity_id.present? ? {"Zuora-Entity-Ids" => self.entity_id, 'Content-Type' => "text/xml; charset=utf-8"} : {'Content-Type' => "text/xml; charset=utf-8"}
|
|
1025
|
-
response = HTTParty.get(url, headers: {"Authorization" => self.get_session(prefix: true, auth_type: :basic)}.merge(headers), :timeout =>
|
|
903
|
+
response = HTTParty.get(url, headers: {"Authorization" => self.get_session(prefix: true, auth_type: :basic)}.merge(headers), :timeout => 120)
|
|
1026
904
|
|
|
1027
905
|
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error.present? ? self.current_error : 'Describe call 401', response) if response.code == 401
|
|
1028
906
|
|
|
@@ -1055,31 +933,35 @@ module ZuoraAPI
|
|
|
1055
933
|
end
|
|
1056
934
|
des_hash[:related_objects] = output_xml.xpath(".//related-objects").xpath(".//object").map{ |x| [x.xpath(".//name").text.to_sym, [ [:url, x.attributes["href"].value], [:label, x.xpath(".//name").text ] ].to_h] }.to_h
|
|
1057
935
|
end
|
|
1058
|
-
|
|
1059
|
-
return des_hash
|
|
1060
936
|
rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
|
|
1061
|
-
if
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
937
|
+
if tries.zero?
|
|
938
|
+
if log_errors
|
|
939
|
+
if Rails.logger.class.to_s == "Ougai::Logger"
|
|
940
|
+
Rails.logger.error("Describe - Timed out will retry after #{self.timeout_sleep} seconds", ex)
|
|
941
|
+
else
|
|
942
|
+
Rails.logger.error("Describe - #{ex.class} Timed out will retry after #{self.timeout_sleep} seconds")
|
|
943
|
+
end
|
|
944
|
+
end
|
|
945
|
+
raise ex
|
|
1066
946
|
end
|
|
1067
947
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
948
|
+
tries -= 1
|
|
949
|
+
sleep(self.timeout_sleep)
|
|
950
|
+
retry
|
|
1071
951
|
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
|
1072
952
|
if !tries.zero? && self.status == 'Active'
|
|
1073
953
|
tries -= 1
|
|
1074
954
|
Rails.logger.debug("Describe session expired. Starting new session.")
|
|
1075
955
|
self.new_session
|
|
1076
956
|
retry
|
|
957
|
+
else
|
|
958
|
+
Rails.logger.error("Describe session expired. Starting new session.") if log_errors
|
|
959
|
+
raise ex
|
|
1077
960
|
end
|
|
1078
|
-
|
|
1079
|
-
Rails.logger.error("Describe session expired. Starting new session.") if log_errors
|
|
1080
|
-
raise ex
|
|
1081
961
|
rescue => ex
|
|
1082
962
|
raise ex
|
|
963
|
+
else
|
|
964
|
+
return des_hash
|
|
1083
965
|
end
|
|
1084
966
|
|
|
1085
967
|
def rest_call(
|
|
@@ -1092,12 +974,11 @@ module ZuoraAPI
|
|
|
1092
974
|
z_session: true,
|
|
1093
975
|
session_type: :basic,
|
|
1094
976
|
timeout_retry: false,
|
|
1095
|
-
timeout:
|
|
977
|
+
timeout: 120,
|
|
1096
978
|
timeout_sleep_interval: self.timeout_sleep,
|
|
1097
979
|
multipart: false,
|
|
1098
980
|
stream_body: false,
|
|
1099
981
|
output_exception_messages: true,
|
|
1100
|
-
zuora_track_id: nil,
|
|
1101
982
|
**keyword_args,
|
|
1102
983
|
&block
|
|
1103
984
|
)
|
|
@@ -1107,13 +988,12 @@ module ZuoraAPI
|
|
|
1107
988
|
|
|
1108
989
|
authentication_headers = {}
|
|
1109
990
|
if z_session
|
|
1110
|
-
authentication_headers = {"Authorization" => self.get_session(prefix: true, auth_type: session_type
|
|
991
|
+
authentication_headers = {"Authorization" => self.get_session(prefix: true, auth_type: session_type) }
|
|
1111
992
|
if self.entity_id.present?
|
|
1112
993
|
authentication_headers["Zuora-Entity-Ids"] = self.entity_id if headers.dig("Zuora-Entity-Ids").nil?
|
|
1113
994
|
authentication_headers.delete_if { |key, value| ["entityId", "entityName"].include?(key.to_s) }
|
|
1114
995
|
end
|
|
1115
996
|
end
|
|
1116
|
-
headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
|
|
1117
997
|
|
|
1118
998
|
modified_headers = {'Content-Type' => "application/json; charset=utf-8"}.merge(authentication_headers).merge(headers)
|
|
1119
999
|
|
|
@@ -1139,20 +1019,18 @@ module ZuoraAPI
|
|
|
1139
1019
|
Rails.logger.debug("Response JSON: #{output_json}") if debug && output_json.present?
|
|
1140
1020
|
|
|
1141
1021
|
raise_errors(type: :JSON, body: output_json, response: response)
|
|
1142
|
-
rescue
|
|
1022
|
+
rescue
|
|
1143
1023
|
reset_files(body) if multipart
|
|
1144
1024
|
raise
|
|
1145
1025
|
end
|
|
1146
|
-
|
|
1147
|
-
return [output_json, response]
|
|
1148
1026
|
rescue ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError => ex
|
|
1149
1027
|
if self.class.to_s == 'ZuoraAPI::Oauth' && ex.message.include?("Authentication type is not supported by this Login")
|
|
1150
1028
|
session_type = :bearer
|
|
1151
1029
|
retry
|
|
1030
|
+
else
|
|
1031
|
+
Rails.logger.debug("Rest Call - Session Bad Auth type")
|
|
1032
|
+
raise ex
|
|
1152
1033
|
end
|
|
1153
|
-
Rails.logger.debug("Rest Call - Session Bad Auth type")
|
|
1154
|
-
raise ex
|
|
1155
|
-
|
|
1156
1034
|
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
|
1157
1035
|
if !tries.zero? && z_session
|
|
1158
1036
|
tries -= 1
|
|
@@ -1165,35 +1043,40 @@ module ZuoraAPI
|
|
|
1165
1043
|
end
|
|
1166
1044
|
|
|
1167
1045
|
retry
|
|
1046
|
+
else
|
|
1047
|
+
if errors.include?(ex.class)
|
|
1048
|
+
raise ex
|
|
1049
|
+
else
|
|
1050
|
+
return [output_json, response]
|
|
1051
|
+
end
|
|
1168
1052
|
end
|
|
1169
|
-
|
|
1170
|
-
raise ex if errors.include?(ex.class)
|
|
1171
|
-
return [output_json, response]
|
|
1172
|
-
|
|
1173
1053
|
rescue *ZUORA_API_ERRORS => ex
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1054
|
+
if errors.include?(ex.class)
|
|
1055
|
+
raise ex
|
|
1056
|
+
else
|
|
1057
|
+
response = ex.response unless response
|
|
1058
|
+
return [output_json, response]
|
|
1059
|
+
end
|
|
1179
1060
|
rescue ZuoraAPI::Exceptions::BadEntityError => ex
|
|
1180
1061
|
raise ex
|
|
1181
1062
|
rescue *CONNECTION_EXCEPTIONS => ex
|
|
1182
|
-
if
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1063
|
+
if tries.zero?
|
|
1064
|
+
if output_exception_messages
|
|
1065
|
+
if Rails.logger.class.to_s == "Ougai::Logger"
|
|
1066
|
+
Rails.logger.error("Rest Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
|
|
1067
|
+
else
|
|
1068
|
+
Rails.logger.error("Rest Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
|
|
1069
|
+
end
|
|
1070
|
+
end
|
|
1071
|
+
raise ex
|
|
1187
1072
|
end
|
|
1188
1073
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1074
|
+
tries -= 1
|
|
1075
|
+
sleep(timeout_sleep_interval)
|
|
1076
|
+
retry
|
|
1192
1077
|
rescue *CONNECTION_READ_EXCEPTIONS => ex
|
|
1193
|
-
|
|
1194
1078
|
if !tries.zero?
|
|
1195
1079
|
tries -= 1
|
|
1196
|
-
self.log(location: "Rest Call", exception: ex, message: "Timed out will retry after #{timeout_sleep_interval} seconds", level: :debug)
|
|
1197
1080
|
if ex.is_a?(Errno::ECONNRESET) && ex.message.include?('SSL_connect')
|
|
1198
1081
|
retry
|
|
1199
1082
|
elsif timeout_retry
|
|
@@ -1201,15 +1084,20 @@ module ZuoraAPI
|
|
|
1201
1084
|
retry
|
|
1202
1085
|
end
|
|
1203
1086
|
end
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1087
|
+
|
|
1088
|
+
if output_exception_messages
|
|
1089
|
+
if Rails.logger.class.to_s == "Ougai::Logger"
|
|
1090
|
+
Rails.logger.error("Rest Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
|
|
1091
|
+
else
|
|
1092
|
+
Rails.logger.error("Rest Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
|
|
1093
|
+
end
|
|
1094
|
+
end
|
|
1095
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received read timeout from #{url}", nil, request) if ex.instance_of?(Net::ReadTimeout)
|
|
1207
1096
|
raise ex
|
|
1208
|
-
|
|
1209
1097
|
rescue => ex
|
|
1210
1098
|
raise ex
|
|
1211
|
-
|
|
1212
|
-
|
|
1099
|
+
else
|
|
1100
|
+
return [output_json, response]
|
|
1213
1101
|
end
|
|
1214
1102
|
|
|
1215
1103
|
def update_create_tenant
|
|
@@ -1231,9 +1119,8 @@ module ZuoraAPI
|
|
|
1231
1119
|
while !response["nextPage"].blank?
|
|
1232
1120
|
url = self.rest_endpoint(response["nextPage"].split('/v1/').last)
|
|
1233
1121
|
Rails.logger.debug("Fetch Catalog URL #{url}")
|
|
1234
|
-
output_json, response = self.rest_call(debug
|
|
1235
|
-
|
|
1236
|
-
if !/(true|t|yes|y|1)$/.match(output_json['success'].to_s) || output_json['success'].class != TrueClass
|
|
1122
|
+
output_json, response = self.rest_call(:debug => false, :url => url, :errors => [ZuoraAPI::Exceptions::ZuoraAPISessionError], :timeout_retry => true )
|
|
1123
|
+
if !output_json['success'] =~ (/(true|t|yes|y|1)$/i) || output_json['success'].class != TrueClass
|
|
1237
1124
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}", response)
|
|
1238
1125
|
end
|
|
1239
1126
|
output_json["products"].each do |product|
|
|
@@ -1259,7 +1146,7 @@ module ZuoraAPI
|
|
|
1259
1146
|
return products, catalog_map
|
|
1260
1147
|
end
|
|
1261
1148
|
|
|
1262
|
-
def get_file(url: nil, headers: {}, z_session: true, tempfile: true, output_file_name: nil, zuora_track_id: nil, add_timestamp: true, file_path: defined?(Rails.root.join('tmp')) ? Rails.root.join('tmp') : Pathname.new(Dir.pwd), timeout_retries: 3, timeout:
|
|
1149
|
+
def get_file(url: nil, headers: {}, z_session: true, tempfile: true, output_file_name: nil, zuora_track_id: nil, add_timestamp: true, file_path: defined?(Rails.root.join('tmp')) ? Rails.root.join('tmp') : Pathname.new(Dir.pwd), timeout_retries: 3, timeout: 120, session_type: :basic, **execute_params)
|
|
1263
1150
|
raise "file_path must be of class Pathname" if file_path.class != Pathname
|
|
1264
1151
|
|
|
1265
1152
|
retry_count ||= timeout_retries
|
|
@@ -1364,20 +1251,14 @@ module ZuoraAPI
|
|
|
1364
1251
|
return file_handle
|
|
1365
1252
|
when Net::HTTPUnauthorized
|
|
1366
1253
|
if z_session
|
|
1367
|
-
|
|
1254
|
+
if !(retry_count -= 1).zero?
|
|
1368
1255
|
self.new_session
|
|
1369
|
-
raise
|
|
1256
|
+
raise response.class
|
|
1257
|
+
else
|
|
1258
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
|
|
1370
1259
|
end
|
|
1371
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
|
|
1372
|
-
end
|
|
1373
|
-
raise
|
|
1374
|
-
when Net::HTTPNotFound
|
|
1375
|
-
if url.include?(self.fileURL)
|
|
1376
|
-
raise ZuoraAPI::Exceptions::FileDownloadError.new(
|
|
1377
|
-
"The current tenant does not have a file with id '#{url.split('/').last}'"
|
|
1378
|
-
)
|
|
1379
1260
|
else
|
|
1380
|
-
raise
|
|
1261
|
+
raise
|
|
1381
1262
|
end
|
|
1382
1263
|
else
|
|
1383
1264
|
raise ZuoraAPI::Exceptions::FileDownloadError.new("File Download Failed #{response.class}")
|
|
@@ -1388,81 +1269,133 @@ module ZuoraAPI
|
|
|
1388
1269
|
sleep(5)
|
|
1389
1270
|
if (retry_count -= 1) >= 0
|
|
1390
1271
|
retry
|
|
1272
|
+
else
|
|
1273
|
+
Rails.logger.error("File Download Failed")
|
|
1274
|
+
raise
|
|
1391
1275
|
end
|
|
1392
|
-
Rails.logger.error("File Download Failed")
|
|
1393
|
-
raise
|
|
1394
1276
|
end
|
|
1395
1277
|
|
|
1396
1278
|
def getDataSourceExport(query, extract: true, encrypted: false, zip: true, z_track_id: "")
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
xml['
|
|
1279
|
+
begin
|
|
1280
|
+
tries ||= 3
|
|
1281
|
+
request = Nokogiri::XML::Builder.new do |xml|
|
|
1282
|
+
xml['SOAP-ENV'].Envelope('xmlns:SOAP-ENV' => "http://schemas.xmlsoap.org/soap/envelope/", 'xmlns:ns2' => "http://object.api.zuora.com/", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", 'xmlns:ns1' => "http://api.zuora.com/") do
|
|
1283
|
+
xml['SOAP-ENV'].Header do
|
|
1284
|
+
xml['ns1'].SessionHeader do
|
|
1285
|
+
xml['ns1'].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: z_track_id)
|
|
1286
|
+
end
|
|
1287
|
+
end
|
|
1288
|
+
xml['SOAP-ENV'].Body do
|
|
1289
|
+
xml['ns1'].create do
|
|
1290
|
+
xml['ns1'].zObjects('xsi:type' => "ns2:Export") do
|
|
1291
|
+
xml['ns2'].Format 'csv'
|
|
1292
|
+
xml['ns2'].Zip zip
|
|
1293
|
+
xml['ns2'].Name 'googman'
|
|
1294
|
+
xml['ns2'].Query query
|
|
1295
|
+
xml['ns2'].Encrypted encrypted
|
|
1296
|
+
end
|
|
1297
|
+
end
|
|
1298
|
+
end
|
|
1407
1299
|
end
|
|
1408
1300
|
end
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1301
|
+
|
|
1302
|
+
response_query = HTTParty.post(self.url, body: request.to_xml(:save_with => XML_SAVE_OPTIONS).strip, headers: {'Content-Type' => "application/json; charset=utf-8", "Z-Track-Id" => z_track_id}, :timeout => 120)
|
|
1303
|
+
|
|
1304
|
+
output_xml = Nokogiri::XML(response_query.body)
|
|
1305
|
+
raise_errors(type: :SOAP, body: output_xml, response: response_query) if output_xml.xpath('//ns1:Success', 'ns1' =>'http://api.zuora.com/').text != "true"
|
|
1306
|
+
|
|
1307
|
+
# raise "Export Creation Unsuccessful : #{response_query.code}: #{response_query.parsed_response}" if output_xml.xpath('//ns1:Success', 'ns1' =>'http://api.zuora.com/').text != "true"
|
|
1308
|
+
|
|
1309
|
+
id = output_xml.xpath('//ns1:Id', 'ns1' =>'http://api.zuora.com/').text
|
|
1310
|
+
|
|
1311
|
+
confirmRequest = Nokogiri::XML::Builder.new do |xml|
|
|
1312
|
+
xml['SOAP-ENV'].Envelope('xmlns:SOAP-ENV' => "http://schemas.xmlsoap.org/soap/envelope/", 'xmlns:ns2' => "http://object.api.zuora.com/", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", 'xmlns:ns1' => "http://api.zuora.com/") do
|
|
1313
|
+
xml['SOAP-ENV'].Header do
|
|
1314
|
+
xml['ns1'].SessionHeader do
|
|
1315
|
+
xml['ns1'].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: z_track_id)
|
|
1316
|
+
end
|
|
1317
|
+
end
|
|
1318
|
+
xml['SOAP-ENV'].Body do
|
|
1319
|
+
xml['ns1'].query do
|
|
1320
|
+
xml['ns1'].queryString "SELECT Id, CreatedById, CreatedDate, Encrypted, FileId, Format, Name, Query, Size, Status, StatusReason, UpdatedById, UpdatedDate, Zip From Export where Id = '#{id}'"
|
|
1321
|
+
end
|
|
1322
|
+
end
|
|
1419
1323
|
end
|
|
1420
1324
|
end
|
|
1421
|
-
result =
|
|
1422
|
-
end
|
|
1325
|
+
result = 'Waiting'
|
|
1423
1326
|
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
if extract && zip
|
|
1429
|
-
require "zip"
|
|
1430
|
-
new_path = export_file_path.partition('.zip').first
|
|
1431
|
-
zipped = Zip::File.open(export_file_path)
|
|
1432
|
-
file_handle = zipped.entries.first
|
|
1433
|
-
file_handle.extract(new_path)
|
|
1434
|
-
File.delete(export_file_path)
|
|
1435
|
-
return new_path
|
|
1436
|
-
else
|
|
1437
|
-
return export_file_path
|
|
1438
|
-
end
|
|
1439
|
-
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
|
1440
|
-
if !(tries -= 1).zero?
|
|
1441
|
-
Rails.logger.info("Export call failed - Trace ID: #{z_track_id}")
|
|
1442
|
-
self.new_session
|
|
1443
|
-
retry
|
|
1444
|
-
end
|
|
1445
|
-
raise ex
|
|
1327
|
+
while result != "Completed"
|
|
1328
|
+
sleep 3
|
|
1329
|
+
response_query = HTTParty.post(self.url, body: confirmRequest.to_xml(:save_with => XML_SAVE_OPTIONS).strip, headers: {'Content-Type' => "application/json; charset=utf-8", "Z-Track-Id" => z_track_id}, :timeout => 120)
|
|
1446
1330
|
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1331
|
+
output_xml = Nokogiri::XML(response_query.body)
|
|
1332
|
+
result = output_xml.xpath('//ns2:Status', 'ns2' =>'http://object.api.zuora.com/').text
|
|
1333
|
+
status_code = response_query.code if response_query
|
|
1334
|
+
|
|
1335
|
+
raise_errors(type: :SOAP, body: output_xml, response: response_query) if result.blank? || result == "Failed"
|
|
1336
|
+
# raise "Export Creation Unsuccessful : #{response_query.code}: #{response_query.parsed_response}" if result.blank? || result == "Failed"
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
file_id = output_xml.xpath('//ns2:FileId', 'ns2' =>'http://object.api.zuora.com/').text
|
|
1340
|
+
export_file = get_file(:url => self.fileURL(file_id))
|
|
1341
|
+
export_file_path = export_file.path
|
|
1342
|
+
Rails.logger.debug("=====> Export path #{export_file.path}")
|
|
1343
|
+
|
|
1344
|
+
if extract && zip
|
|
1345
|
+
require "zip"
|
|
1346
|
+
new_path = export_file_path.partition('.zip').first
|
|
1347
|
+
zipped = Zip::File.open(export_file_path)
|
|
1348
|
+
file_handle = zipped.entries.first
|
|
1349
|
+
file_handle.extract(new_path)
|
|
1350
|
+
File.delete(export_file_path)
|
|
1351
|
+
return new_path
|
|
1352
|
+
else
|
|
1353
|
+
return export_file_path
|
|
1354
|
+
end
|
|
1355
|
+
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
|
1356
|
+
if !(tries -= 1).zero?
|
|
1357
|
+
Rails.logger.info("Export call failed - Trace ID: #{z_track_id}")
|
|
1358
|
+
self.new_session
|
|
1359
|
+
retry
|
|
1360
|
+
else
|
|
1361
|
+
raise ex
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
rescue ZuoraAPI::Exceptions::ZuoraUnexpectedError => ex
|
|
1365
|
+
if !(tries -= 1).zero?
|
|
1366
|
+
Rails.logger.info("Trace ID: #{z_track_id} UnexpectedError, will retry after 10 seconds")
|
|
1367
|
+
sleep 10
|
|
1368
|
+
retry
|
|
1369
|
+
else
|
|
1370
|
+
raise ex
|
|
1371
|
+
end
|
|
1372
|
+
|
|
1373
|
+
rescue *ZUORA_API_ERRORS => ex
|
|
1374
|
+
raise ex
|
|
1375
|
+
|
|
1376
|
+
rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
|
|
1377
|
+
if !(tries -= 1).zero?
|
|
1378
|
+
Rails.logger.info("Trace ID: #{z_track_id} Timed out will retry after 5 seconds")
|
|
1379
|
+
sleep 5
|
|
1380
|
+
retry
|
|
1381
|
+
else
|
|
1382
|
+
raise ex
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
rescue Errno::ECONNRESET => ex
|
|
1386
|
+
if !(tries -= 1).zero? && ex.message.include?('SSL_connect')
|
|
1387
|
+
retry
|
|
1388
|
+
else
|
|
1389
|
+
raise ex
|
|
1390
|
+
end
|
|
1391
|
+
|
|
1392
|
+
rescue ZuoraAPI::Exceptions::BadEntityError => ex
|
|
1393
|
+
raise ex
|
|
1460
1394
|
end
|
|
1461
|
-
raise ex
|
|
1462
1395
|
end
|
|
1463
1396
|
|
|
1464
1397
|
def query(query, parse = false)
|
|
1465
|
-
output_xml, input_xml = self.soap_call(debug
|
|
1398
|
+
output_xml, input_xml = self.soap_call({:debug => false, :timeout_retry => true}) do |xml|
|
|
1466
1399
|
xml['ns1'].query do
|
|
1467
1400
|
xml['ns1'].queryString query
|
|
1468
1401
|
end
|